Skip to content

Commit

Permalink
fix(types): do not erase component type constraint (#410)
Browse files Browse the repository at this point in the history
  • Loading branch information
mcous authored Nov 19, 2024
1 parent acbddfd commit 90ba912
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ public/bundle.*
coverage
dist
.idea
*.tgz

# These cause more harm than good when working with contributors
yarn-error.log
Expand Down
17 changes: 17 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
8 changes: 8 additions & 0 deletions src/__tests__/render.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
Expand Down
44 changes: 28 additions & 16 deletions src/component-types.d.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,53 @@
/* 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.
*
* 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.
*
* 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

Expand All @@ -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]

0 comments on commit 90ba912

Please sign in to comment.