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<any> extends (...args: any[]) => any ? true : false + /** A compiled, imported Svelte component. */ export type Component< - P extends Record<string, any>, - E extends Record<string, any>, + P extends Record<string, any> = any, + E extends Record<string, any> = any, > = IS_MODERN_SVELTE extends true - ? Svelte.Component<P, E> | Svelte.SvelteComponent<P> - : Svelte.SvelteComponent<P> + ? ModernComponent<P, E> | LegacyComponent<P> + : IS_LEGACY_SVELTE_4 extends true + ? LegacyComponent<P> + : Svelte3LegacyComponent<P> /** * 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<C> = IS_MODERN_SVELTE extends true - ? C - : new (...args: any[]) => C +export type ComponentType<C> = C extends LegacyComponent + ? new (...args: any[]) => C + : C /** The props of a component. */ -export type Props<C extends Component<any, any>> = Svelte.ComponentProps<C> +export type Props<C extends Component> = ComponentProps<C> /** * The exported fields of a component. @@ -32,9 +45,9 @@ export type Props<C extends Component<any, any>> = Svelte.ComponentProps<C> * 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> = C extends Svelte.SvelteComponent +export type Exports<C> = C extends LegacyComponent ? C - : C extends Svelte.Component<any, infer E> + : C extends ModernComponent<any, infer E> ? E : never @@ -43,7 +56,6 @@ export type Exports<C> = C extends Svelte.SvelteComponent * * In Svelte 4, these are the options passed to the component constructor. */ -export type MountOptions<C extends Component<any, any>> = - IS_MODERN_SVELTE extends true - ? Parameters<typeof Svelte.mount<Props<C>, Exports<C>>>[1] - : Svelte.ComponentConstructorOptions<Props<C>> +export type MountOptions<C extends Component> = C extends LegacyComponent + ? LegacyConstructorOptions<Props<C>> + : Parameters<typeof mount<Props<C>, Exports<C>>>[1]