Skip to content

Commit a8e616b

Browse files
author
Simon
committed
Adjust way of adding types to output, add more convenience types
Closes sveltejs#7584
1 parent 995c509 commit a8e616b

File tree

6 files changed

+58
-38
lines changed

6 files changed

+58
-38
lines changed

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
"pretest": "npm run build",
9696
"posttest": "agadoo internal/index.mjs",
9797
"prepublishOnly": "node check_publish_env.js && npm run lint && npm test",
98-
"tsd": "tsc -p src/compiler --emitDeclarationOnly && tsc -p src/runtime --emitDeclarationOnly && node ./post-typegen.js",
98+
"tsd": "node ./tsd.js",
9999
"lint": "eslint \"{src,test}/**/*.{ts,js}\""
100100
},
101101
"repository": {

post-typegen.js

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/runtime/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ export {
1212
tick,
1313
createEventDispatcher,
1414
SvelteComponentDev as SvelteComponent,
15-
SvelteComponentTyped
15+
SvelteComponentTyped,
16+
// additional exports added through post-typegen.js
1617
} from 'svelte/internal';
17-
export type { SvelteComponentConstructor } from 'svelte/internal';

src/runtime/internal/dev.ts

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ export interface SvelteComponentDev {
128128
$destroy(): void;
129129
[accessor: string]: any;
130130
}
131-
interface IComponentOptions<Props extends Record<string, any> = Record<string, any>> {
131+
export interface ComponentConstructorParams<Props extends Record<string, any> = Record<string, any>> {
132132
target: Element | ShadowRoot;
133133
anchor?: Element;
134134
props?: Props;
@@ -164,7 +164,7 @@ export class SvelteComponentDev extends SvelteComponent {
164164
*/
165165
$$slot_def: any;
166166

167-
constructor(options: IComponentOptions) {
167+
constructor(options: ComponentConstructorParams) {
168168
if (!options || (!options.target && !options.$$inline)) {
169169
throw new Error("'target' is a required option");
170170
}
@@ -256,26 +256,47 @@ export class SvelteComponentTyped<
256256
*/
257257
$$slot_def: Slots;
258258

259-
constructor(options: IComponentOptions<Props>) {
259+
constructor(options: ComponentConstructorParams<Props>) {
260260
super(options);
261261
}
262262
}
263263

264264
/**
265-
* Convenience-type to represent a Svelte component constructor.
265+
* Convenience type to get the type of a Svelte component. Useful for example in combination with
266+
* dynamic components and `<svelte:element>`.
266267
*
267268
* Example:
268-
* ```ts
269-
import ASvelteComponent from './ASvelteComponent.svelte';
270-
const ComponentClass: SvelteComponentConstructor = ASvelteComponent;
271-
new ComponentClass(..);
272-
```
269+
* ```html
270+
* <script lang="ts">
271+
* import { ComponentType, SvelteComponentTyped } from 'svelte';
272+
* import Component1 from './Component1.svelte';
273+
* import Component2 from './Component2.svelte';
274+
*
275+
* const component: ComponentType = someLogic() ? Component1 : Component2;
276+
* const componentOfCertainSubType: ComponentType<SvelteComponentTyped<{needsThisProp: string}>> = someLogic() ? Component1 : Component2;
277+
* </script>
278+
*
279+
* <svelte:element this={component} />
280+
* <svelte:element this={componentOfCertainSubType} needsThisProp="hello" />
281+
* ```
273282
*/
274-
export type SvelteComponentConstructor<
275-
Props extends Record<string, any> = any,
276-
Events extends Record<string, any> = any,
277-
Slots extends Record<string, any> = any
278-
> = new (options: IComponentOptions<Props>) => SvelteComponentTyped<Props, Events, Slots>;
283+
export type ComponentType<T extends SvelteComponentTyped = SvelteComponentTyped<any, any, any>> =
284+
new (p: ComponentConstructorParams<T extends SvelteComponentTyped<infer X, any, any> ? X : any>) => T;
285+
286+
/**
287+
* Convenience type to get the properties the given component expects. Example:
288+
* ```html
289+
* <script lang="ts">
290+
* import { ComponentProps } from 'svelte';
291+
* import Component from './Component.svelte';
292+
*
293+
* const props: ComponentProps<Component> = { foo: 'bar' }; // Errors if these aren't the correct props
294+
* </script>
295+
* ```
296+
*/
297+
export type ComponentProps<T extends SvelteComponent> = T extends SvelteComponentTyped<infer Props>
298+
? Props
299+
: unknown;
279300

280301
export function loop_guard(timeout) {
281302
const start = Date.now();

tsd.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// This script generates the TypeScript definitions
2+
3+
const { execSync } = require('child_process');
4+
const { readFileSync, writeFileSync } = require('fs');
5+
6+
execSync('tsc -p src/compiler --emitDeclarationOnly && tsc -p src/runtime --emitDeclarationOnly');
7+
8+
// We need to add these types to the index.d.ts here because if we add them before building, the build will fail,
9+
// because the TS->JS transformation doesn't know these exports are types and produces code that fails at runtime.
10+
// We can't use `export type` syntax either because the TS version we're on doesn't have this feature yet.
11+
const path = 'types/runtime/index.d.ts';
12+
const content = readFileSync(path, 'utf8');
13+
writeFileSync(path, content.replace('SvelteComponentTyped', 'SvelteComponentTyped, ComponentType, ComponentConstructorParams, ComponentProps'));

0 commit comments

Comments
 (0)