diff --git a/packages/language-core/lib/codegen/globalTypes.ts b/packages/language-core/lib/codegen/globalTypes.ts index ac0a213671..2a9b1e06fb 100644 --- a/packages/language-core/lib/codegen/globalTypes.ts +++ b/packages/language-core/lib/codegen/globalTypes.ts @@ -97,6 +97,9 @@ export function generateGlobalTypes(lib: string, target: number, strictTemplates '__ctx' extends keyof __VLS_PickNotAny ? K extends { __ctx?: infer Ctx } ? Ctx : never : any , T extends (props: any, ctx: infer Ctx) => any ? Ctx : any >>; + type __VLS_OmitStringIndex = { + [K in keyof T as string extends K ? never : K]: T[K]; + }; type __VLS_UseTemplateRef = Readonly>; function __VLS_getVForSourceType(source: number): [number, number, number][]; diff --git a/packages/language-core/lib/codegen/template/context.ts b/packages/language-core/lib/codegen/template/context.ts index 662ee6cff2..a9b797162e 100644 --- a/packages/language-core/lib/codegen/template/context.ts +++ b/packages/language-core/lib/codegen/template/context.ts @@ -106,14 +106,14 @@ export function createTemplateCodegenContext(options: Pick>(); const slots: { name: string; - loc?: number; + offset?: number; tagRange: [number, number]; - varName: string; nodeLoc: any; + propsVar: string; }[] = []; const dynamicSlots: { expVar: string; - varName: string; + propsVar: string; }[] = []; const hasSlotElements = new Set();; const blockConditions: string[] = []; diff --git a/packages/language-core/lib/codegen/template/index.ts b/packages/language-core/lib/codegen/template/index.ts index 63bcdfa5d6..e5c8637155 100644 --- a/packages/language-core/lib/codegen/template/index.ts +++ b/packages/language-core/lib/codegen/template/index.ts @@ -54,21 +54,23 @@ export function* generateTemplate(options: TemplateCodegenOptions): Generator { + const name = getSlotsPropertyName(options.vueCompilerOptions.target); + if (!options.hasDefineSlots) { - yield `var __VLS_slots!: `; - for (const { expVar, varName } of ctx.dynamicSlots) { + yield `var __VLS_slots!: __VLS_OmitStringIndex & `; + for (const { expVar, propsVar } of ctx.dynamicSlots) { ctx.hasSlot = true; - yield `Partial, (_: typeof ${varName}) => any>> &${newLine}`; + yield `Partial, (props: typeof ${propsVar}) => any>> &${newLine}`; } yield `{${newLine}`; for (const slot of ctx.slots) { ctx.hasSlot = true; - if (slot.name && slot.loc !== undefined) { + if (slot.name && slot.offset !== undefined) { yield* generateObjectProperty( options, ctx, slot.name, - slot.loc, + slot.offset, ctx.codeFeatures.withoutHighlightAndCompletion, slot.nodeLoc ); @@ -81,11 +83,10 @@ function* generateSlots(options: TemplateCodegenOptions, ctx: TemplateCodegenCon `default` ); } - yield `?(_: typeof ${slot.varName}): any,${newLine}`; + yield `?(props: typeof ${slot.propsVar}): any,${newLine}`; } yield `}${endOfLine}`; } - const name = getSlotsPropertyName(options.vueCompilerOptions.target); yield `var ${name}!: typeof ${options.slotsAssignName ?? '__VLS_slots'}${endOfLine}`; } diff --git a/packages/language-core/lib/codegen/template/slotOutlet.ts b/packages/language-core/lib/codegen/template/slotOutlet.ts index a8b07fb40c..eae8d8c1b6 100644 --- a/packages/language-core/lib/codegen/template/slotOutlet.ts +++ b/packages/language-core/lib/codegen/template/slotOutlet.ts @@ -14,7 +14,7 @@ export function* generateSlotOutlet( node: CompilerDOM.SlotOutletNode ): Generator { const startTagOffset = node.loc.start.offset + options.template.content.slice(node.loc.start.offset).indexOf(node.tag); - const varSlot = ctx.getInternalVariable(); + const propsVar = ctx.getInternalVariable(); const nameProp = node.props.find(prop => { if (prop.type === CompilerDOM.NodeTypes.ATTRIBUTE) { return prop.name === 'name'; @@ -43,7 +43,7 @@ export function* generateSlotOutlet( ? `'${nameProp.value.content}'` : nameProp?.type === CompilerDOM.NodeTypes.DIRECTIVE && nameProp.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION ? nameProp.exp.content - : `('default' as const)` + : `'default'` ), `]` ); @@ -59,7 +59,7 @@ export function* generateSlotOutlet( yield `)${endOfLine}`; } else { - yield `var ${varSlot} = {${newLine}`; + yield `var ${propsVar} = {${newLine}`; yield* generateElementProps(options, ctx, node, node.props.filter(prop => prop !== nameProp), options.vueCompilerOptions.strictTemplates, true); yield `}${endOfLine}`; @@ -69,10 +69,10 @@ export function* generateSlotOutlet( ) { ctx.slots.push({ name: nameProp.value.content, - loc: nameProp.loc.start.offset + nameProp.loc.source.indexOf(nameProp.value.content, nameProp.name.length), + offset: nameProp.loc.start.offset + nameProp.loc.source.indexOf(nameProp.value.content, nameProp.name.length), tagRange: [startTagOffset, startTagOffset + node.tag.length], - varName: varSlot, nodeLoc: node.loc, + propsVar, }); } else if ( @@ -83,8 +83,8 @@ export function* generateSlotOutlet( if (isShortHand) { ctx.inlayHints.push(createVBindShorthandInlayHintInfo(nameProp.exp.loc, 'name')); } - const slotExpVar = ctx.getInternalVariable(); - yield `var ${slotExpVar} = `; + const expVar = ctx.getInternalVariable(); + yield `var ${expVar} = __VLS_tryAsConstant(`; yield* generateInterpolation( options, ctx, @@ -92,22 +92,20 @@ export function* generateSlotOutlet( ctx.codeFeatures.all, nameProp.exp.content, nameProp.exp.loc.start.offset, - nameProp.exp, - '(', - ')' + nameProp.exp ); - yield ` as const${endOfLine}`; + yield `)${endOfLine}`; ctx.dynamicSlots.push({ - expVar: slotExpVar, - varName: varSlot, + expVar, + propsVar, }); } else { ctx.slots.push({ name: 'default', tagRange: [startTagOffset, startTagOffset + node.tag.length], - varName: varSlot, nodeLoc: node.loc, + propsVar, }); } } diff --git a/packages/tsc/tests/__snapshots__/dts.spec.ts.snap b/packages/tsc/tests/__snapshots__/dts.spec.ts.snap index 6959c4430d..bd1df52836 100644 --- a/packages/tsc/tests/__snapshots__/dts.spec.ts.snap +++ b/packages/tsc/tests/__snapshots__/dts.spec.ts.snap @@ -11,8 +11,10 @@ declare const _default: (__VLS_props: NonNullable> & (import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps); expose(exposed: import("vue").ShallowUnwrapRef<{}>): void; attrs: any; - slots: { - default?(_: { + slots: __VLS_OmitStringIndex; + }>> & { + default?(props: { row: Row; }): any; }; @@ -619,15 +621,17 @@ export {}; exports[`vue-tsc-dts > Input: template-slots/component.vue, Output: template-slots/component.vue.d.ts 1`] = ` "declare function __VLS_template(): { attrs: Partial<{}>; - slots: { - 'no-bind'?(_: {}): any; - default?(_: { + slots: __VLS_OmitStringIndex; + }>> & { + 'no-bind'?(props: {}): any; + default?(props: { num: number; }): any; - 'named-slot'?(_: { + 'named-slot'?(props: { str: string; }): any; - vbind?(_: { + vbind?(props: { num: number; str: string; }): any; @@ -721,15 +725,17 @@ type __VLS_WithTemplateSlots = T & { exports[`vue-tsc-dts > Input: template-slots/component-no-script.vue, Output: template-slots/component-no-script.vue.d.ts 1`] = ` "declare function __VLS_template(): { attrs: Partial<{}>; - slots: { - 'no-bind'?(_: {}): any; - default?(_: { + slots: __VLS_OmitStringIndex; + }>> & { + 'no-bind'?(props: {}): any; + default?(props: { num: number; }): any; - 'named-slot'?(_: { + 'named-slot'?(props: { str: string; }): any; - vbind?(_: { + vbind?(props: { num: number; str: string; }): any; diff --git a/test-workspace/tsc/passedFixtures/vue3/slots/main.vue b/test-workspace/tsc/passedFixtures/vue3/slots/main.vue index ed4b9556f7..3c7a441714 100644 --- a/test-workspace/tsc/passedFixtures/vue3/slots/main.vue +++ b/test-workspace/tsc/passedFixtures/vue3/slots/main.vue @@ -1,5 +1,5 @@