diff --git a/.changeset/fair-spies-repeat.md b/.changeset/fair-spies-repeat.md new file mode 100644 index 000000000000..fc4a7dbd2f74 --- /dev/null +++ b/.changeset/fair-spies-repeat.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +breaking: make `$props()` rune non-generic diff --git a/packages/svelte/elements.d.ts b/packages/svelte/elements.d.ts index 7e3b5a7ffa99..2dff32045d59 100644 --- a/packages/svelte/elements.d.ts +++ b/packages/svelte/elements.d.ts @@ -67,7 +67,7 @@ export type ToggleEventHandler = EventHandler { // Implicit children prop every element has - // Add this here so that libraries doing `$props()` don't need a separate interface + // Add this here so that libraries doing `let { ...props }: HTMLButtonAttributes = $props()` don't need a separate interface children?: import('svelte').Snippet; // Clipboard Events diff --git a/packages/svelte/src/main/ambient.d.ts b/packages/svelte/src/main/ambient.d.ts index 9d7f1d84c14d..1cb02f9f4d16 100644 --- a/packages/svelte/src/main/ambient.d.ts +++ b/packages/svelte/src/main/ambient.d.ts @@ -172,12 +172,12 @@ declare namespace $effect { * Declares the props that a component accepts. Example: * * ```ts - * let { optionalProp = 42, requiredProp } = $props<{ optionalProp?: number; requiredProps: string}>(); + * let { optionalProp = 42, requiredProp }: { optionalProp?: number; requiredProps: string } = $props(); * ``` * * https://svelte-5-preview.vercel.app/docs/runes#$props */ -declare function $props(): T; +declare function $props(): any; /** * Inspects one or more values whenever they, or the properties they contain, change. Example: diff --git a/packages/svelte/src/main/public.d.ts b/packages/svelte/src/main/public.d.ts index aaf771e46079..180c91b0116a 100644 --- a/packages/svelte/src/main/public.d.ts +++ b/packages/svelte/src/main/public.d.ts @@ -186,7 +186,7 @@ declare const SnippetReturn: unique symbol; /** * The type of a `#snippet` block. You can use it to (for example) express that your component expects a snippet of a certain type: * ```ts - * let { banner } = $props<{ banner: Snippet<{ text: string }> }>(); + * let { banner }: { banner: Snippet<{ text: string }> } = $props(); * ``` * You can only call a snippet through the `{@render ...}` tag. */ diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index aa0156846303..06b27b06a718 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -187,7 +187,7 @@ declare module 'svelte' { /** * The type of a `#snippet` block. You can use it to (for example) express that your component expects a snippet of a certain type: * ```ts - * let { banner } = $props<{ banner: Snippet<{ text: string }> }>(); + * let { banner }: { banner: Snippet<{ text: string }> } = $props(); * ``` * You can only call a snippet through the `{@render ...}` tag. */ @@ -1879,7 +1879,7 @@ declare module 'svelte/legacy' { /** * The type of a `#snippet` block. You can use it to (for example) express that your component expects a snippet of a certain type: * ```ts - * let { banner } = $props<{ banner: Snippet<{ text: string }> }>(); + * let { banner }: { banner: Snippet<{ text: string }> } = $props(); * ``` * You can only call a snippet through the `{@render ...}` tag. */ @@ -2615,12 +2615,12 @@ declare namespace $effect { * Declares the props that a component accepts. Example: * * ```ts - * let { optionalProp = 42, requiredProp } = $props<{ optionalProp?: number; requiredProps: string}>(); + * let { optionalProp = 42, requiredProp }: { optionalProp?: number; requiredProps: string } = $props(); * ``` * * https://svelte-5-preview.vercel.app/docs/runes#$props */ -declare function $props(): T; +declare function $props(): any; /** * Inspects one or more values whenever they, or the properties they contain, change. Example: diff --git a/sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md b/sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md index 850daabb4560..f2b557066df2 100644 --- a/sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md +++ b/sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md @@ -465,14 +465,23 @@ To get all properties, use rest syntax: let { a, b, c, ...everythingElse } = $props(); ``` -If you're using TypeScript, you can use type arguments: +If you're using TypeScript, you can declare the prop types: ```ts type MyProps = any; // ---cut--- -let { a, b, c, ...everythingElse } = $props(); +let { a, b, c, ...everythingElse }: MyProps = $props(); ``` +> In an earlier preview, `$props()` took a type argument. This caused bugs, since in a case like this... +> +> ```ts +> // @errors: 2558 +> let { x = 42 } = $props<{ x: string }>(); +> ``` +> +> ...TypeScript [widens the type](https://www.typescriptlang.org/play?#code/CYUwxgNghgTiAEAzArgOzAFwJYHtXwBIAHGHIgZwB4AVeAXnilQE8A+ACgEoAueagbgBQgiCAzwA3vAAe9eABYATPAC+c4qQqUp03uQwwsqAOaqOnIfCsB6a-AB6AfiA) of `x` to be `string | number`, instead of erroring. + Props cannot be mutated, unless the parent component uses `bind:`. During development, attempts to mutate props will result in an error. ### What this replaces diff --git a/sites/svelte-5-preview/src/routes/docs/content/01-api/03-snippets.md b/sites/svelte-5-preview/src/routes/docs/content/01-api/03-snippets.md index 850de82f38c5..e10443f7505b 100644 --- a/sites/svelte-5-preview/src/routes/docs/content/01-api/03-snippets.md +++ b/sites/svelte-5-preview/src/routes/docs/content/01-api/03-snippets.md @@ -229,11 +229,11 @@ Snippets implement the `Snippet` interface imported from `'svelte'`: + ``` @@ -246,13 +246,13 @@ We can tighten things up further by declaring a generic, so that `data` and `row + ``` diff --git a/sites/svelte-5-preview/src/routes/docs/render.js b/sites/svelte-5-preview/src/routes/docs/render.js index 66881926f957..5d44f48bad0b 100644 --- a/sites/svelte-5-preview/src/routes/docs/render.js +++ b/sites/svelte-5-preview/src/routes/docs/render.js @@ -166,7 +166,7 @@ const render_content = (filename, body) => twoslashBanner: (filename, source) => { const injected = [ `// @filename: runes.d.ts`, - `declare function $props(): T`, + `declare function $props(): any`, `declare function $state(initial: T): T`, `declare function $derived(value: T): T`, `declare const $effect: ((callback: () => void | (() => void)) => void) & { pre: (callback: () => void | (() => void)) => void };`