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 7 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> {
// 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;
// Clipboard Events

@ -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>(): T;
declare function $props(): any;
/**
* 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:
* ```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.
*/

@ -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.
*/
@ -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:
* ```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.
*/
@ -2624,12 +2624,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>(): T;
declare function $props(): any;
/**
* 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();
```
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<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.
### What this replaces

@ -229,11 +229,11 @@ Snippets implement the `Snippet` interface imported from `'svelte'`:
+<script lang="ts">
+ import type { Snippet } from 'svelte';
+
+ let { data, children, row } = $props<{
+ let { data, children, row }: {
+ data: any[];
+ children: Snippet;
+ row: Snippet<[any]>;
+ }>();
+ } = $props();
</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">
import type { Snippet } from 'svelte';
let { data, children, row } = $props<{
let { data, children, row }: {
- data: any[];
+ data: T[];
children: Snippet;
- row: Snippet<[any]>;
+ row: Snippet<[T]>;
}>();
} = $props();
</script>
```

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

Loading…
Cancel
Save