Skip to content

Commit f568869

Browse files
authored
fix(language-core): correct type inference of multiple template refs with same name (#5271)
1 parent e07b797 commit f568869

File tree

4 files changed

+45
-21
lines changed

4 files changed

+45
-21
lines changed

packages/language-core/lib/codegen/template/context.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ export function createTemplateCodegenContext(options: Pick<TemplateCodegenOption
175175
const templateRefs = new Map<string, {
176176
typeExp: string;
177177
offset: number;
178-
}>();
178+
}[]>();
179179

180180
return {
181181
codeFeatures: new Proxy(codeFeatures, {
@@ -203,6 +203,13 @@ export function createTemplateCodegenContext(options: Pick<TemplateCodegenOption
203203
} | undefined,
204204
singleRootElTypes: [] as string[],
205205
singleRootNodes: new Set<CompilerDOM.ElementNode | null>(),
206+
addTemplateRef: (name: string, typeExp: string, offset: number) => {
207+
let refs = templateRefs.get(name);
208+
if (!refs) {
209+
templateRefs.set(name, refs = []);
210+
}
211+
refs.push({ typeExp, offset });
212+
},
206213
accessExternalVariable(name: string, offset?: number) {
207214
let arr = accessExternalVariables.get(name);
208215
if (!arr) {

packages/language-core/lib/codegen/template/element.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,7 @@ export function* generateComponent(
264264
yield `${endOfLine}`;
265265

266266
if (refName && offset) {
267-
ctx.templateRefs.set(refName, {
268-
typeExp: `typeof ${ctx.getHoistVariable(componentInstanceVar)}`,
269-
offset
270-
});
267+
ctx.addTemplateRef(refName, `typeof ${ctx.getHoistVariable(componentInstanceVar)}`, offset);
271268
}
272269
if (isRootNode) {
273270
ctx.singleRootElTypes.push(`NonNullable<typeof ${componentInstanceVar}>['$el']`);
@@ -355,10 +352,7 @@ export function* generateElement(
355352
if (isVForChild) {
356353
typeExp += `[]`;
357354
}
358-
ctx.templateRefs.set(refName, {
359-
typeExp,
360-
offset
361-
});
355+
ctx.addTemplateRef(refName, typeExp, offset);
362356
}
363357
if (ctx.singleRootNodes.has(node)) {
364358
ctx.singleRootElTypes.push(`__VLS_NativeElements['${node.tag}']`);

packages/language-core/lib/codegen/template/index.ts

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -140,18 +140,32 @@ function* generateTemplateRefs(
140140
options: TemplateCodegenOptions,
141141
ctx: TemplateCodegenContext
142142
): Generator<Code> {
143-
yield `type __VLS_TemplateRefs = {${newLine}`;
144-
for (const [name, { typeExp, offset }] of ctx.templateRefs) {
145-
yield* generateObjectProperty(
146-
options,
147-
ctx,
148-
name,
149-
offset,
150-
ctx.codeFeatures.navigationAndCompletion
151-
);
152-
yield `: ${typeExp},${newLine}`;
153-
}
154-
yield `}${endOfLine}`;
143+
yield `type __VLS_TemplateRefs = {}`;
144+
for (const [name, refs] of ctx.templateRefs) {
145+
yield `${newLine}& `;
146+
if (refs.length >= 2) {
147+
yield `(`;
148+
}
149+
for (let i = 0; i < refs.length; i++) {
150+
const { typeExp, offset } = refs[i];
151+
if (i) {
152+
yield ` | `;
153+
}
154+
yield `{ `;
155+
yield* generateObjectProperty(
156+
options,
157+
ctx,
158+
name,
159+
offset,
160+
ctx.codeFeatures.navigation
161+
);
162+
yield `: ${typeExp} }`;
163+
}
164+
if (refs.length >= 2) {
165+
yield `)`;
166+
}
167+
}
168+
yield endOfLine;
155169
return `__VLS_TemplateRefs`;
156170
}
157171

test-workspace/tsc/passedFixtures/vue3/templateRef/template-refs.vue

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ if (comp4.value) {
2525
exactType(comp4.value, {} as HTMLAnchorElement[]);
2626
}
2727
28+
const comp5 = useTemplateRef('multiple');
29+
if (comp5.value) {
30+
exactType(comp5.value, {} as HTMLAnchorElement | HTMLDivElement);
31+
}
32+
2833
// @ts-expect-error
2934
useTemplateRef('unknown');
3035
</script>
@@ -41,4 +46,8 @@ useTemplateRef('unknown');
4146

4247
<a v-for="i in 3" ref="v-for-native" :key="i"></a>
4348
{{ exactType(comp4?.[0]?.href, {} as string | undefined) }}
49+
50+
<a ref="multiple"></a>
51+
<div ref="multiple"></div>
52+
{{ exactType(comp5, {} as HTMLAnchorElement | HTMLDivElement | null) }}
4453
</template>

0 commit comments

Comments
 (0)