breaking: make `$props()` rune non-generic (#10694)

* breaking: make `$props()` rune non-generic

* explain why type argument was removed

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
pull/10776/head
Rich Harris 8 months ago committed by GitHub
parent 7212a56296
commit 77f39ea988
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
breaking: make `$props()` rune non-generic

@ -67,7 +67,7 @@ export type ToggleEventHandler<T extends EventTarget> = EventHandler<ToggleEvent
export interface DOMAttributes<T extends EventTarget> { export interface DOMAttributes<T extends EventTarget> {
// Implicit children prop every element has // Implicit children prop every element has
// Add this here so that libraries doing `$props<HTMLButtonAttributes>()` 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; children?: import('svelte').Snippet;
// Clipboard Events // Clipboard Events

@ -172,12 +172,12 @@ declare namespace $effect {
* Declares the props that a component accepts. Example: * Declares the props that a component accepts. Example:
* *
* ```ts * ```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 * https://svelte-5-preview.vercel.app/docs/runes#$props
*/ */
declare function $props<T>(): T; declare function $props(): any;
/** /**
* Inspects one or more values whenever they, or the properties they contain, change. Example: * Inspects one or more values whenever they, or the properties they contain, change. Example:

@ -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: * 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 * ```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. * You can only call a snippet through the `{@render ...}` tag.
*/ */

@ -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: * 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 * ```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. * You can only call a snippet through the `{@render ...}` tag.
*/ */
@ -1888,7 +1888,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: * 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 * ```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. * You can only call a snippet through the `{@render ...}` tag.
*/ */
@ -2624,12 +2624,12 @@ declare namespace $effect {
* Declares the props that a component accepts. Example: * Declares the props that a component accepts. Example:
* *
* ```ts * ```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 * https://svelte-5-preview.vercel.app/docs/runes#$props
*/ */
declare function $props<T>(): T; declare function $props(): any;
/** /**
* Inspects one or more values whenever they, or the properties they contain, change. Example: * Inspects one or more values whenever they, or the properties they contain, change. Example:

@ -454,14 +454,23 @@ To get all properties, use rest syntax:
let { a, b, c, ...everythingElse } = $props(); 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 ```ts
type MyProps = any; type MyProps = any;
// ---cut--- // ---cut---
let { a, b, c, ...everythingElse } = $props<MyProps>(); 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. Props cannot be mutated, unless the parent component uses `bind:`. During development, attempts to mutate props will result in an error.
### What this replaces ### What this replaces

@ -229,11 +229,11 @@ Snippets implement the `Snippet` interface imported from `'svelte'`:
+<script lang="ts"> +<script lang="ts">
+ import type { Snippet } from 'svelte'; + import type { Snippet } from 'svelte';
+ +
+ let { data, children, row } = $props<{ + let { data, children, row }: {
+ data: any[]; + data: any[];
+ children: Snippet; + children: Snippet;
+ row: Snippet<[any]>; + row: Snippet<[any]>;
+ }>(); + } = $props();
</script> </script>
``` ```
@ -246,13 +246,13 @@ We can tighten things up further by declaring a generic, so that `data` and `row
+<script lang="ts" generics="T"> +<script lang="ts" generics="T">
import type { Snippet } from 'svelte'; import type { Snippet } from 'svelte';
let { data, children, row } = $props<{ let { data, children, row }: {
- data: any[]; - data: any[];
+ data: T[]; + data: T[];
children: Snippet; children: Snippet;
- row: Snippet<[any]>; - row: Snippet<[any]>;
+ row: Snippet<[T]>; + row: Snippet<[T]>;
}>(); } = $props();
</script> </script>
``` ```

@ -166,7 +166,7 @@ const render_content = (filename, body) =>
twoslashBanner: (filename, source) => { twoslashBanner: (filename, source) => {
const injected = [ const injected = [
`// @filename: runes.d.ts`, `// @filename: runes.d.ts`,
`declare function $props<T>(): T`, `declare function $props(): any`,
`declare function $state<T>(initial: T): T`, `declare function $state<T>(initial: T): T`,
`declare function $derived<T>(value: T): T`, `declare function $derived<T>(value: T): T`,
`declare const $effect: ((callback: () => void | (() => void)) => void) & { pre: (callback: () => void | (() => void)) => void };` `declare const $effect: ((callback: () => void | (() => void)) => void) & { pre: (callback: () => void | (() => void)) => void };`

Loading…
Cancel
Save