Skip to content

Commit

Permalink
feat: add ComponentExports utility type (#13441)
Browse files Browse the repository at this point in the history
Safer/clearer/backwards/forward-compatibale way to reference them

---------

Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
  • Loading branch information
FoHoOV and dummdidumm authored Oct 31, 2024
1 parent 3999fed commit d93ad3b
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/rotten-cups-float.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

chore: provide `ComponentExports` utility type
20 changes: 20 additions & 0 deletions packages/svelte/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,26 @@ export type ComponentProps<Comp extends SvelteComponent | Component<any, any>> =
? Props
: never;

/**
* Convenience type to get the properties that given component exports.
*
* Example: Typing the `bind:this` for a component named `MyComponent`
* ```
* <script lang="ts">
* import MyComponent from '$lib/component';
* let component: ComponentExports<typeof MyComponent> | undefined = undefined;
* <script>
*
* <MyComponent bind:this={component} />
* ```
*/
export type ComponentExports<TComponent extends Component<any, any> | typeof SvelteComponent<any>> =
TComponent extends typeof SvelteComponent<any>
? InstanceType<TComponent>
: TComponent extends Component<any, infer TExports>
? TExports
: never;

/**
* @deprecated This type is obsolete when working with the new `Component` type.
*
Expand Down
26 changes: 25 additions & 1 deletion packages/svelte/tests/types/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
mount,
hydrate,
type Component,
type ComponentInternals
type ComponentInternals,
type ComponentExports
} from 'svelte';
import { render } from 'svelte/server';

Expand Down Expand Up @@ -180,6 +181,16 @@ render(NewComponent, {
}
});

const newComponentExports: ComponentExports<typeof NewComponent> = {
anExport: '',
$$events_def: null as any,
$$prop_def: null as any,
$$slot_def: null as any,
$set: null as any,
$destroy: null as any,
$on: null as any
};

// --------------------------------------------------------------------------- interop

const AsLegacyComponent = asClassComponent(newComponent);
Expand Down Expand Up @@ -337,6 +348,19 @@ render(functionComponent, {
}
});

const functionComponentExports: ComponentExports<typeof functionComponent> = {
foo: 'bar',
// @ts-expect-error
x: ''
};

type AdhocFunctionComponent = (a: unknown, b: { a: true }) => { foo: string };
const adhocFunctionComponentExport: ComponentExports<AdhocFunctionComponent> = {
foo: 'bar',
// @ts-expect-error
x: ''
};

// --------------------------------------------------------------------------- *.svelte components

// import from a nonexistent file to trigger the declare module '*.svelte' in ambient.d.ts
Expand Down
20 changes: 20 additions & 0 deletions packages/svelte/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,26 @@ declare module 'svelte' {
? Props
: never;

/**
* Convenience type to get the properties that given component exports.
*
* Example: Typing the `bind:this` for a component named `MyComponent`
* ```
* <script lang="ts">
* import MyComponent from '$lib/component';
* let component: ComponentExports<typeof MyComponent> | undefined = undefined;
* <script>
*
* <MyComponent bind:this={component} />
* ```
*/
export type ComponentExports<TComponent extends Component<any, any> | typeof SvelteComponent<any>> =
TComponent extends typeof SvelteComponent<any>
? InstanceType<TComponent>
: TComponent extends Component<any, infer TExports>
? TExports
: never;

/**
* @deprecated This type is obsolete when working with the new `Component` type.
*
Expand Down

0 comments on commit d93ad3b

Please sign in to comment.