Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fair-spies-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

breaking: make `$props()` rune non-generic
2 changes: 1 addition & 1 deletion packages/svelte/elements.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions packages/svelte/src/main/ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte/src/main/public.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
8 changes: 4 additions & 4 deletions packages/svelte/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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>(): T;
declare function $props(): any;

/**
* Inspects one or more values whenever they, or the properties they contain, change. Example:
Expand Down
13 changes: 11 additions & 2 deletions sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<MyProps>();
let { a, b, c, ...everythingElse }: MyProps = $props();
```

dummdidumm marked this conversation as resolved.
Show resolved Hide resolved
> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>
```

Expand All @@ -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>
```

Expand Down
2 changes: 1 addition & 1 deletion sites/svelte-5-preview/src/routes/docs/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 };`
Expand Down
Loading