From 634e3084b37122bb48251d1f7df8c95f2ed248a6 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Mon, 17 Jun 2024 16:58:59 +0200 Subject: [PATCH] fix: support function invocation from imported `*.svelte` components When the TypeScript plugin we provide isn't enabled, imports to `.svelte`-files fall back to an ambient module declaration. Said declaration was still only providing the deprecated class. This PR widens the type so that you can also invoke it like a function. After the transition period (Svelte 6 or 7) only the new type should be provided from the module declaration. --- .changeset/ninety-days-visit.md | 5 +++++ packages/svelte/src/ambient.d.ts | 13 ++++++++++++- packages/svelte/tests/types/component.ts | 10 ++++++++++ packages/svelte/types/index.d.ts | 13 ++++++++++++- 4 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 .changeset/ninety-days-visit.md diff --git a/.changeset/ninety-days-visit.md b/.changeset/ninety-days-visit.md new file mode 100644 index 000000000000..51e6e5267ec5 --- /dev/null +++ b/.changeset/ninety-days-visit.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: support function invocation from imported `*.svelte` components diff --git a/packages/svelte/src/ambient.d.ts b/packages/svelte/src/ambient.d.ts index d024c5d5213b..04ad31acf1d0 100644 --- a/packages/svelte/src/ambient.d.ts +++ b/packages/svelte/src/ambient.d.ts @@ -1,5 +1,16 @@ declare module '*.svelte' { - export { SvelteComponent as default } from 'svelte'; + import { SvelteComponent, Component, type ComponentConstructorOptions } from 'svelte'; + + // Support using the component as both a class and function during the transition period + interface ComponentType { + ( + ...args: Parameters>> + ): ReturnType, Record>>; + new (o: ComponentConstructorOptions): SvelteComponent; + } + const Comp: ComponentType; + type Comp = SvelteComponent; + export default Comp; } /** diff --git a/packages/svelte/tests/types/component.ts b/packages/svelte/tests/types/component.ts index 101927a46976..ca520656fd91 100644 --- a/packages/svelte/tests/types/component.ts +++ b/packages/svelte/tests/types/component.ts @@ -281,3 +281,13 @@ render(functionComponent, { x: '' } }); + +// --------------------------------------------------------------------------- *.svelte components + +// import from a nonexistent file to trigger the declare module '*.svelte' in ambient.d.ts +// this could show an error in the future in the editor (because language tools intercepts and knows this is an error) +// but should always pass in tsc (because it will never know about this fact) +import Foo from './doesntexist.svelte'; + +Foo(null, { a: true }); +const f: Foo = new Foo({ target: document.body, props: { a: true } }); diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 742e048c9528..4afd0698b63d 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -2634,7 +2634,18 @@ declare module 'svelte/types/compiler/interfaces' { */ type Namespace = 'html' | 'svg' | 'mathml' | 'foreign'; }declare module '*.svelte' { - export { SvelteComponent as default } from 'svelte'; + import { SvelteComponent, Component, type ComponentConstructorOptions } from 'svelte'; + + // Support using the component as both a class and function during the transition period + interface ComponentType { + ( + ...args: Parameters>> + ): ReturnType, Record>>; + new (o: ComponentConstructorOptions): SvelteComponent; + } + const Comp: ComponentType; + type Comp = SvelteComponent; + export default Comp; } /**