From 90ba912d4609d36168732a39e7fe6f99a35330a1 Mon Sep 17 00:00:00 2001 From: Michael Cousins Date: Tue, 19 Nov 2024 12:20:36 -0500 Subject: [PATCH] fix(types): do not erase component type constraint (#410) --- .github/workflows/release.yml | 2 +- .gitignore | 1 + CONTRIBUTING.md | 17 +++++++++++++ package.json | 5 +++- src/__tests__/render.test-d.ts | 8 +++++++ src/component-types.d.ts | 44 +++++++++++++++++++++------------- 6 files changed, 59 insertions(+), 18 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3f432da..1251be8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -52,7 +52,7 @@ jobs: node-version: ${{ matrix.node }} - name: 📥 Download deps - run: ./scripts/install-dependencies ${{ matrix.svelte }} + run: npm run install:${{ matrix.svelte }} - name: ▶️ Run ${{ matrix.check }} run: npm run ${{ matrix.check }} diff --git a/.gitignore b/.gitignore index 151e826..ca3410b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ public/bundle.* coverage dist .idea +*.tgz # These cause more harm than good when working with contributors yarn-error.log diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 92856ee..4c40705 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -58,6 +58,23 @@ npm test npm run test:watch ``` +### Using different versions of Svelte + +Use the provided script to set up your environment for different versions of Svelte: + +```shell +# install Svelte 5 +npm run install:5 + +# install Svelte 4 +npm run install:4 + +# install Svelte 3 +npm run install:3 +``` + +Not all checks will pass on `svelte<5`. Reference the CI workflows to see which checks are expected to pass on older versions. + ### Docs Use the `toc` script to ensure the README's table of contents is up to date: diff --git a/package.json b/package.json index 0788f40..b65e953 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,10 @@ "build": "tsc -p tsconfig.build.json && cp src/component-types.d.ts types", "contributors:add": "all-contributors add", "contributors:generate": "all-contributors generate", - "preview-release": "./scripts/preview-release" + "preview-release": "./scripts/preview-release", + "install:3": "./scripts/install-dependencies 3", + "install:4": "./scripts/install-dependencies 4", + "install:5": "./scripts/install-dependencies 5" }, "peerDependencies": { "svelte": "^3 || ^4 || ^5 || ^5.0.0-next.0", diff --git a/src/__tests__/render.test-d.ts b/src/__tests__/render.test-d.ts index 5b1e16a..08cad70 100644 --- a/src/__tests__/render.test-d.ts +++ b/src/__tests__/render.test-d.ts @@ -18,6 +18,14 @@ describe('types', () => { await rerender({ count: 0 }) }) + test('non-components are rejected', () => { + // eslint-disable-next-line @typescript-eslint/no-extraneous-class + class NotComponent {} + + // @ts-expect-error: component should be a Svelte component + subject.render(NotComponent) + }) + test('invalid prop types are rejected', () => { // @ts-expect-error: name should be a string subject.render(Component, { name: 42 }) diff --git a/src/component-types.d.ts b/src/component-types.d.ts index 2e4a5a5..9f707c2 100644 --- a/src/component-types.d.ts +++ b/src/component-types.d.ts @@ -1,17 +1,30 @@ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-redundant-type-constituents */ -import type * as Svelte from 'svelte' +import type { + Component as ModernComponent, + ComponentConstructorOptions as LegacyConstructorOptions, + ComponentProps, + EventDispatcher, + mount, + SvelteComponent as LegacyComponent, + SvelteComponentTyped as Svelte3LegacyComponent, +} from 'svelte' -type IS_MODERN_SVELTE = Svelte.Component extends (...args: any[]) => any +type IS_MODERN_SVELTE = ModernComponent extends (...args: any[]) => any ? true : false +type IS_LEGACY_SVELTE_4 = + EventDispatcher extends (...args: any[]) => any ? true : false + /** A compiled, imported Svelte component. */ export type Component< - P extends Record, - E extends Record, + P extends Record = any, + E extends Record = any, > = IS_MODERN_SVELTE extends true - ? Svelte.Component | Svelte.SvelteComponent

- : Svelte.SvelteComponent

+ ? ModernComponent | LegacyComponent

+ : IS_LEGACY_SVELTE_4 extends true + ? LegacyComponent

+ : Svelte3LegacyComponent

/** * The type of an imported, compiled Svelte component. @@ -19,12 +32,12 @@ export type Component< * In Svelte 5, this distinction no longer matters. * In Svelte 4, this is the Svelte component class constructor. */ -export type ComponentType = IS_MODERN_SVELTE extends true - ? C - : new (...args: any[]) => C +export type ComponentType = C extends LegacyComponent + ? new (...args: any[]) => C + : C /** The props of a component. */ -export type Props> = Svelte.ComponentProps +export type Props = ComponentProps /** * The exported fields of a component. @@ -32,9 +45,9 @@ export type Props> = Svelte.ComponentProps * In Svelte 5, this is the set of variables marked as `export`'d. * In Svelte 4, this is simply the instance of the component class. */ -export type Exports = C extends Svelte.SvelteComponent +export type Exports = C extends LegacyComponent ? C - : C extends Svelte.Component + : C extends ModernComponent ? E : never @@ -43,7 +56,6 @@ export type Exports = C extends Svelte.SvelteComponent * * In Svelte 4, these are the options passed to the component constructor. */ -export type MountOptions> = - IS_MODERN_SVELTE extends true - ? Parameters, Exports>>[1] - : Svelte.ComponentConstructorOptions> +export type MountOptions = C extends LegacyComponent + ? LegacyConstructorOptions> + : Parameters, Exports>>[1]