Skip to content

Commit 4715dfa

Browse files
feat: migrate Component to ComponentExports<typeof Component> in TS (#13656)
Closes #13491 --------- Co-authored-by: Simon Holthausen <[email protected]>
1 parent d93ad3b commit 4715dfa

File tree

4 files changed

+77
-5
lines changed

4 files changed

+77
-5
lines changed

.changeset/new-parrots-pay.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: migrate `Component` to `ComponentExports<typeof Component>` in TS

packages/svelte/src/compiler/migrate/index.js

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/** @import { VariableDeclarator, Node, Identifier, AssignmentExpression, LabeledStatement, ExpressionStatement } from 'estree' */
2-
/** @import { Visitors } from 'zimmerframe' */
2+
/** @import { Visitors, Context } from 'zimmerframe' */
33
/** @import { ComponentAnalysis } from '../phases/types.js' */
44
/** @import { Scope, ScopeRoot } from '../phases/scope.js' */
55
/** @import { AST, Binding, SvelteNode, ValidatedCompileOptions } from '#compiler' */
@@ -398,6 +398,8 @@ export function migrate(source, { filename, use_ts } = {}) {
398398
}
399399
}
400400

401+
/** @typedef {SvelteNode | { type: "TSTypeReference", typeName: Identifier, start: number, end: number }} ASTNode */
402+
401403
/**
402404
* @typedef {{
403405
* scope: Scope;
@@ -416,11 +418,12 @@ export function migrate(source, { filename, use_ts } = {}) {
416418
* derived_components: Map<string, string>;
417419
* derived_labeled_statements: Set<LabeledStatement>;
418420
* has_svelte_self: boolean;
421+
* migrate_prop_component_type?: boolean;
419422
* uses_ts: boolean;
420423
* }} State
421424
*/
422425

423-
/** @type {Visitors<SvelteNode, State>} */
426+
/** @type {Visitors<ASTNode, State>} */
424427
const instance_script = {
425428
_(node, { state, next }) {
426429
// @ts-expect-error
@@ -437,8 +440,27 @@ const instance_script = {
437440
}
438441
next();
439442
},
440-
Identifier(node, { state, path }) {
443+
TSTypeReference(node, { state, path }) {
444+
if (state.analysis.runes) return;
445+
if (node.typeName.type === 'Identifier') {
446+
const binding = state.scope.get(node.typeName.name);
447+
if (
448+
binding &&
449+
binding.declaration_kind === 'import' &&
450+
binding.initial?.type === 'ImportDeclaration' &&
451+
binding.initial.source.value?.toString().endsWith('.svelte')
452+
) {
453+
state.str.overwrite(
454+
node.start,
455+
node.end,
456+
`import('svelte').ComponentExports<typeof ${state.str.original.substring(node.start, node.end)}>`
457+
);
458+
}
459+
}
460+
},
461+
Identifier(node, { state, path, next }) {
441462
handle_identifier(node, state, path);
463+
next();
442464
},
443465
ImportDeclaration(node, { state }) {
444466
state.props_insertion_point = node.end ?? state.props_insertion_point;
@@ -503,6 +525,8 @@ const instance_script = {
503525
return;
504526
}
505527

528+
next();
529+
506530
let nr_of_props = 0;
507531

508532
for (const declarator of node.declarations) {
@@ -1409,7 +1433,7 @@ function migrate_slot_usage(node, path, state) {
14091433
/**
14101434
* @param {VariableDeclarator} declarator
14111435
* @param {State} state
1412-
* @param {SvelteNode[]} path
1436+
* @param {ASTNode[]} path
14131437
*/
14141438
function extract_type_and_comment(declarator, state, path) {
14151439
const str = state.str;
@@ -1432,7 +1456,10 @@ function extract_type_and_comment(declarator, state, path) {
14321456
while (str.original[start] === ' ') {
14331457
start++;
14341458
}
1435-
return { type: str.original.substring(start, declarator.id.typeAnnotation.end), comment };
1459+
return {
1460+
type: str.snip(start, declarator.id.typeAnnotation.end).toString(),
1461+
comment
1462+
};
14361463
}
14371464

14381465
let cleaned_comment_arr = comment
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<script lang="ts">
2+
import Component from "./Component.svelte";
3+
import type ComponentType from "./Component.svelte";
4+
5+
export let my_comp: Component;
6+
7+
export let my_component_type: ComponentType;
8+
9+
export function enhance(comp: Component, comp_type: ComponentType){
10+
11+
}
12+
13+
let comp: Component | ComponentType | undefined = undefined;
14+
15+
export const the_comp: Component | ComponentType = comp;
16+
</script>
17+
18+
<Component bind:this={comp} />
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<script lang="ts">
2+
import Component from "./Component.svelte";
3+
import type ComponentType from "./Component.svelte";
4+
5+
6+
interface Props {
7+
my_comp: import('svelte').ComponentExports<typeof Component>;
8+
my_component_type: import('svelte').ComponentExports<typeof ComponentType>;
9+
}
10+
11+
let { my_comp, my_component_type }: Props = $props();
12+
13+
export function enhance(comp: import('svelte').ComponentExports<typeof Component>, comp_type: import('svelte').ComponentExports<typeof ComponentType>){
14+
15+
}
16+
17+
let comp: import('svelte').ComponentExports<typeof Component> | import('svelte').ComponentExports<typeof ComponentType> | undefined = $state(undefined);
18+
19+
export const the_comp: import('svelte').ComponentExports<typeof Component> | import('svelte').ComponentExports<typeof ComponentType> = comp;
20+
</script>
21+
22+
<Component bind:this={comp} />

0 commit comments

Comments
 (0)