Skip to content

Commit 77f39ea

Browse files
authored
breaking: make $props() rune non-generic (#10694)
* breaking: make `$props()` rune non-generic * explain why type argument was removed --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 7212a56 commit 77f39ea

File tree

8 files changed

+29
-15
lines changed

8 files changed

+29
-15
lines changed

.changeset/fair-spies-repeat.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
breaking: make `$props()` rune non-generic

packages/svelte/elements.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export type ToggleEventHandler<T extends EventTarget> = EventHandler<ToggleEvent
6767

6868
export interface DOMAttributes<T extends EventTarget> {
6969
// Implicit children prop every element has
70-
// Add this here so that libraries doing `$props<HTMLButtonAttributes>()` don't need a separate interface
70+
// Add this here so that libraries doing `let { ...props }: HTMLButtonAttributes = $props()` don't need a separate interface
7171
children?: import('svelte').Snippet;
7272

7373
// Clipboard Events

packages/svelte/src/main/ambient.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,12 @@ declare namespace $effect {
172172
* Declares the props that a component accepts. Example:
173173
*
174174
* ```ts
175-
* let { optionalProp = 42, requiredProp } = $props<{ optionalProp?: number; requiredProps: string}>();
175+
* let { optionalProp = 42, requiredProp }: { optionalProp?: number; requiredProps: string } = $props();
176176
* ```
177177
*
178178
* https://svelte-5-preview.vercel.app/docs/runes#$props
179179
*/
180-
declare function $props<T>(): T;
180+
declare function $props(): any;
181181

182182
/**
183183
* Inspects one or more values whenever they, or the properties they contain, change. Example:

packages/svelte/src/main/public.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ declare const SnippetReturn: unique symbol;
186186
/**
187187
* The type of a `#snippet` block. You can use it to (for example) express that your component expects a snippet of a certain type:
188188
* ```ts
189-
* let { banner } = $props<{ banner: Snippet<{ text: string }> }>();
189+
* let { banner }: { banner: Snippet<{ text: string }> } = $props();
190190
* ```
191191
* You can only call a snippet through the `{@render ...}` tag.
192192
*/

packages/svelte/types/index.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ declare module 'svelte' {
187187
/**
188188
* The type of a `#snippet` block. You can use it to (for example) express that your component expects a snippet of a certain type:
189189
* ```ts
190-
* let { banner } = $props<{ banner: Snippet<{ text: string }> }>();
190+
* let { banner }: { banner: Snippet<{ text: string }> } = $props();
191191
* ```
192192
* You can only call a snippet through the `{@render ...}` tag.
193193
*/
@@ -1888,7 +1888,7 @@ declare module 'svelte/legacy' {
18881888
/**
18891889
* The type of a `#snippet` block. You can use it to (for example) express that your component expects a snippet of a certain type:
18901890
* ```ts
1891-
* let { banner } = $props<{ banner: Snippet<{ text: string }> }>();
1891+
* let { banner }: { banner: Snippet<{ text: string }> } = $props();
18921892
* ```
18931893
* You can only call a snippet through the `{@render ...}` tag.
18941894
*/
@@ -2624,12 +2624,12 @@ declare namespace $effect {
26242624
* Declares the props that a component accepts. Example:
26252625
*
26262626
* ```ts
2627-
* let { optionalProp = 42, requiredProp } = $props<{ optionalProp?: number; requiredProps: string}>();
2627+
* let { optionalProp = 42, requiredProp }: { optionalProp?: number; requiredProps: string } = $props();
26282628
* ```
26292629
*
26302630
* https://svelte-5-preview.vercel.app/docs/runes#$props
26312631
*/
2632-
declare function $props<T>(): T;
2632+
declare function $props(): any;
26332633

26342634
/**
26352635
* Inspects one or more values whenever they, or the properties they contain, change. Example:

sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,14 +454,23 @@ To get all properties, use rest syntax:
454454
let { a, b, c, ...everythingElse } = $props();
455455
```
456456

457-
If you're using TypeScript, you can use type arguments:
457+
If you're using TypeScript, you can declare the prop types:
458458

459459
```ts
460460
type MyProps = any;
461461
// ---cut---
462-
let { a, b, c, ...everythingElse } = $props<MyProps>();
462+
let { a, b, c, ...everythingElse }: MyProps = $props();
463463
```
464464

465+
> In an earlier preview, `$props()` took a type argument. This caused bugs, since in a case like this...
466+
>
467+
> ```ts
468+
> // @errors: 2558
469+
> let { x = 42 } = $props<{ x: string }>();
470+
> ```
471+
>
472+
> ...TypeScript [widens the type](https://www.typescriptlang.org/play?#code/CYUwxgNghgTiAEAzArgOzAFwJYHtXwBIAHGHIgZwB4AVeAXnilQE8A+ACgEoAueagbgBQgiCAzwA3vAAe9eABYATPAC+c4qQqUp03uQwwsqAOaqOnIfCsB6a-AB6AfiA) of `x` to be `string | number`, instead of erroring.
473+
465474
Props cannot be mutated, unless the parent component uses `bind:`. During development, attempts to mutate props will result in an error.
466475
467476
### What this replaces

sites/svelte-5-preview/src/routes/docs/content/01-api/03-snippets.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,11 @@ Snippets implement the `Snippet` interface imported from `'svelte'`:
229229
+<script lang="ts">
230230
+ import type { Snippet } from 'svelte';
231231
+
232-
+ let { data, children, row } = $props<{
232+
+ let { data, children, row }: {
233233
+ data: any[];
234234
+ children: Snippet;
235235
+ row: Snippet<[any]>;
236-
+ }>();
236+
+ } = $props();
237237
</script>
238238
```
239239

@@ -246,13 +246,13 @@ We can tighten things up further by declaring a generic, so that `data` and `row
246246
+<script lang="ts" generics="T">
247247
import type { Snippet } from 'svelte';
248248

249-
let { data, children, row } = $props<{
249+
let { data, children, row }: {
250250
- data: any[];
251251
+ data: T[];
252252
children: Snippet;
253253
- row: Snippet<[any]>;
254254
+ row: Snippet<[T]>;
255-
}>();
255+
} = $props();
256256
</script>
257257
```
258258

sites/svelte-5-preview/src/routes/docs/render.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ const render_content = (filename, body) =>
166166
twoslashBanner: (filename, source) => {
167167
const injected = [
168168
`// @filename: runes.d.ts`,
169-
`declare function $props<T>(): T`,
169+
`declare function $props(): any`,
170170
`declare function $state<T>(initial: T): T`,
171171
`declare function $derived<T>(value: T): T`,
172172
`declare const $effect: ((callback: () => void | (() => void)) => void) & { pre: (callback: () => void | (() => void)) => void };`

0 commit comments

Comments
 (0)