fix: relax `Component` type (#11929)

The current type narrows the binding type to `""` by default, which means "no bindings on this component". While this is the common case, it makes it very cumbersome to use the `Component` type because legacy components are of type `string` and as soon as you have bindings, the type is something like `"foo" | "bar"` which _also_ is not assignable to `""` which is semantically wrong, because you should be able to assign a component that can have bindings to a type that accepts none.
The pragmatic solution is to change the binding type to allow `string`, which means someone theoretically could use bindings with a component that doesn't have bindings:
```svelte
<script>
  let component: Component<{ prop: boolean }> = IAcceptNoBindings;
</script>
<!-- allowed but should be a type error -->
<svelte:component this={component} bind:prop={foo} />
```
But this is a) rare anyway and b) can be caught at runtime

This came up in comments of #11775
pull/11926/head
Simon H 7 months ago committed by GitHub
parent 08b5851a66
commit 5b0a843b31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: relax `Component` type

@ -129,7 +129,7 @@ export class SvelteComponent<
export interface Component< export interface Component<
Props extends Record<string, any> = {}, Props extends Record<string, any> = {},
Exports extends Record<string, any> = {}, Exports extends Record<string, any> = {},
Bindings extends keyof Props | '' = '' Bindings extends keyof Props | '' = string
> { > {
/** /**
* @param internal An internal object used by Svelte. Do not use or modify. * @param internal An internal object used by Svelte. Do not use or modify.

@ -204,6 +204,8 @@ const functionComponent: Component<
}; };
functionComponent.element === HTMLElement; functionComponent.element === HTMLElement;
const bindingIsOkayToWiden: Component<any> = functionComponent;
functionComponent(null as any, { functionComponent(null as any, {
binding: true, binding: true,
// @ts-expect-error // @ts-expect-error

@ -126,7 +126,7 @@ declare module 'svelte' {
export interface Component< export interface Component<
Props extends Record<string, any> = {}, Props extends Record<string, any> = {},
Exports extends Record<string, any> = {}, Exports extends Record<string, any> = {},
Bindings extends keyof Props | '' = '' Bindings extends keyof Props | '' = string
> { > {
/** /**
* @param internal An internal object used by Svelte. Do not use or modify. * @param internal An internal object used by Svelte. Do not use or modify.
@ -1990,7 +1990,7 @@ declare module 'svelte/legacy' {
* *
* */ * */
export function createClassComponent<Props extends Record<string, any>, Exports extends Record<string, any>, Events extends Record<string, any>, Slots extends Record<string, any>>(options: import("svelte").ComponentConstructorOptions<Props> & { export function createClassComponent<Props extends Record<string, any>, Exports extends Record<string, any>, Events extends Record<string, any>, Slots extends Record<string, any>>(options: import("svelte").ComponentConstructorOptions<Props> & {
component: import("svelte").ComponentType<import("svelte").SvelteComponent<Props, Events, Slots>> | import("svelte").Component<Props, any, "">; component: import("svelte").ComponentType<import("svelte").SvelteComponent<Props, Events, Slots>> | import("svelte").Component<Props, any, string>;
immutable?: boolean | undefined; immutable?: boolean | undefined;
hydrate?: boolean | undefined; hydrate?: boolean | undefined;
recover?: boolean | undefined; recover?: boolean | undefined;
@ -2001,7 +2001,7 @@ declare module 'svelte/legacy' {
* @deprecated Use this only as a temporary solution to migrate your imperative component code to Svelte 5. * @deprecated Use this only as a temporary solution to migrate your imperative component code to Svelte 5.
* *
* */ * */
export function asClassComponent<Props extends Record<string, any>, Exports extends Record<string, any>, Events extends Record<string, any>, Slots extends Record<string, any>>(component: import("svelte").SvelteComponent<Props, Events, Slots> | import("svelte").Component<Props, any, "">): import("svelte").ComponentType<import("svelte").SvelteComponent<Props, Events, Slots> & Exports>; export function asClassComponent<Props extends Record<string, any>, Exports extends Record<string, any>, Events extends Record<string, any>, Slots extends Record<string, any>>(component: import("svelte").SvelteComponent<Props, Events, Slots> | import("svelte").Component<Props, any, string>): import("svelte").ComponentType<import("svelte").SvelteComponent<Props, Events, Slots> & Exports>;
/** /**
* Runs the given function once immediately on the server, and works like `$effect.pre` on the client. * Runs the given function once immediately on the server, and works like `$effect.pre` on the client.
* *

Loading…
Cancel
Save