diff --git a/packages/language-core/lib/codegen/globalTypes.ts b/packages/language-core/lib/codegen/globalTypes.ts index da8debd067..5c6b22a285 100644 --- a/packages/language-core/lib/codegen/globalTypes.ts +++ b/packages/language-core/lib/codegen/globalTypes.ts @@ -126,6 +126,9 @@ export function generateGlobalTypes({ '__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][]; diff --git a/packages/language-core/lib/codegen/template/context.ts b/packages/language-core/lib/codegen/template/context.ts index c435b70f44..bb28955542 100644 --- a/packages/language-core/lib/codegen/template/context.ts +++ b/packages/language-core/lib/codegen/template/context.ts @@ -107,14 +107,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 blockConditions: string[] = []; const scopedClasses: { diff --git a/packages/language-core/lib/codegen/template/index.ts b/packages/language-core/lib/codegen/template/index.ts index 4e7c05efbf..a6becd5c5e 100644 --- a/packages/language-core/lib/codegen/template/index.ts +++ b/packages/language-core/lib/codegen/template/index.ts @@ -67,34 +67,39 @@ function* generateSlots( options: TemplateCodegenOptions, ctx: TemplateCodegenContext ): Generator { + const name = getSlotsPropertyName(options.vueCompilerOptions.target); if (!options.hasDefineSlots) { - yield `var __VLS_slots!: __VLS_PrettifyGlobal<{}`; - for (const { expVar, varName } of ctx.dynamicSlots) { - ctx.hasSlot = true; - yield `${newLine}& { [K in NonNullable]?: (props: typeof ${varName}) => any }`; - } - for (const slot of ctx.slots) { - yield `${newLine}& { `; - ctx.hasSlot = true; - if (slot.name && slot.loc !== undefined) { - yield* generateObjectProperty( - options, - ctx, - slot.name, - slot.loc, - ctx.codeFeatures.withoutHighlightAndCompletion, - slot.nodeLoc - ); + yield `var __VLS_slots!: __VLS_PrettifyGlobal<__VLS_OmitStringIndex`; + if (ctx.dynamicSlots.length || ctx.slots.length) { + yield ` & Readonly<`; + for (const { expVar, propsVar } of ctx.dynamicSlots) { + ctx.hasSlot = true; + yield `${newLine}& { [K in NonNullable]?: (props: typeof ${propsVar}) => any }`; } - else { - yield* wrapWith( - slot.tagRange[0], - slot.tagRange[1], - ctx.codeFeatures.withoutHighlightAndCompletion, - `default` - ); + for (const slot of ctx.slots) { + yield `${newLine}& { `; + ctx.hasSlot = true; + if (slot.name && slot.offset !== undefined) { + yield* generateObjectProperty( + options, + ctx, + slot.name, + slot.offset, + ctx.codeFeatures.withoutHighlightAndCompletion, + slot.nodeLoc + ); + } + else { + yield* wrapWith( + slot.tagRange[0], + slot.tagRange[1], + ctx.codeFeatures.withoutHighlightAndCompletion, + `default` + ); + } + yield `?: (props: typeof ${slot.propsVar}) => any }`; } - yield `?: (props: typeof ${slot.varName}) => any }`; + yield `${newLine}>`; } yield `>${endOfLine}`; } diff --git a/packages/language-core/lib/codegen/template/slotOutlet.ts b/packages/language-core/lib/codegen/template/slotOutlet.ts index 332e433f67..2a9007eb15 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'` ), `]` ); @@ -66,7 +66,7 @@ export function* generateSlotOutlet( yield `)${endOfLine}`; } else { - yield `var ${varSlot} = {${newLine}`; + yield `var ${propsVar} = {${newLine}`; yield* generateElementProps( options, ctx, @@ -83,10 +83,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 ( @@ -97,8 +97,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, @@ -106,22 +106,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 61012811d4..af3eb6bdba 100644 --- a/packages/tsc/tests/__snapshots__/dts.spec.ts.snap +++ b/packages/tsc/tests/__snapshots__/dts.spec.ts.snap @@ -12,7 +12,7 @@ declare const _default: (__VLS_props: NonNullable): void; attrs: any; slots: { - default?: (props: { + readonly default?: (props: { row: Row; }) => any; }; @@ -594,7 +594,8 @@ export {}; `; exports[`vue-tsc-dts > Input: template-slots/component.vue, Output: template-slots/component.vue.d.ts 1`] = ` -"declare var __VLS_0: {}; +"declare const __VLS_ctx: InstanceType<__VLS_PickNotAny {}>>; +declare var __VLS_0: {}; declare var __VLS_1: { num: number; }; @@ -605,7 +606,7 @@ declare var __VLS_3: { num: number; str: string; }; -declare var __VLS_slots: __VLS_PrettifyGlobal<{} & { +declare var __VLS_slots: __VLS_PrettifyGlobal<__VLS_OmitStringIndex & Readonly<{ 'no-bind'?: (props: typeof __VLS_0) => any; } & { default?: (props: typeof __VLS_1) => any; @@ -613,8 +614,9 @@ declare var __VLS_slots: __VLS_PrettifyGlobal<{} & { 'named-slot'?: (props: typeof __VLS_2) => any; } & { vbind?: (props: typeof __VLS_3) => any; -}>; +}>>; type __VLS_TemplateSlots = typeof __VLS_slots; +declare const __VLS_self: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; declare const _default: __VLS_WithTemplateSlots; export default _default; @@ -688,7 +690,8 @@ 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 var __VLS_0: {}; +"declare const __VLS_ctx: InstanceType<__VLS_PickNotAny {}>>; +declare var __VLS_0: {}; declare var __VLS_1: { num: number; }; @@ -699,7 +702,7 @@ declare var __VLS_3: { num: number; str: string; }; -declare var __VLS_slots: __VLS_PrettifyGlobal<{} & { +declare var __VLS_slots: __VLS_PrettifyGlobal<__VLS_OmitStringIndex & Readonly<{ 'no-bind'?: (props: typeof __VLS_0) => any; } & { default?: (props: typeof __VLS_1) => any; @@ -707,8 +710,9 @@ declare var __VLS_slots: __VLS_PrettifyGlobal<{} & { 'named-slot'?: (props: typeof __VLS_2) => any; } & { vbind?: (props: typeof __VLS_3) => any; -}>; +}>>; type __VLS_TemplateSlots = typeof __VLS_slots; +declare const __VLS_self: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; declare const _default: __VLS_WithTemplateSlots; export default _default; diff --git a/test-workspace/tsc/passedFixtures/vue3/slots/main.vue b/test-workspace/tsc/passedFixtures/vue3/slots/main.vue index bccbfa97bf..a438bbca86 100644 --- a/test-workspace/tsc/passedFixtures/vue3/slots/main.vue +++ b/test-workspace/tsc/passedFixtures/vue3/slots/main.vue @@ -1,5 +1,5 @@