diff --git a/packages/component-meta/tests/index.spec.ts b/packages/component-meta/tests/index.spec.ts index f1f443977e..ac4ac3521a 100644 --- a/packages/component-meta/tests/index.spec.ts +++ b/packages/component-meta/tests/index.spec.ts @@ -535,6 +535,19 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) => describ expect(onBaz?.schema).toEqual([]); }); + test('reference-type-events for generic', () => { + const componentPath = path.resolve(__dirname, '../../../test-workspace/component-meta/generic/component.vue'); + const meta = checker.getComponentMeta(componentPath); + + expect(meta.type).toEqual(TypeMeta.Function); + + const onBar = meta.events.find(event => event.name === 'bar'); + + expect(onBar).toBeDefined(); + expect(onBar?.type).toEqual('number'); + expect(onBar?.signature).toEqual('(e: "bar", data: number): void'); + }); + test('template-slots', () => { const componentPath = path.resolve(__dirname, '../../../test-workspace/component-meta/template-slots/component.vue'); const meta = checker.getComponentMeta(componentPath); @@ -563,6 +576,18 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) => describ expect(d).toBeDefined(); }); + test('template-slots for generic', () => { + const componentPath = path.resolve(__dirname, '../../../test-workspace/component-meta/generic/component.vue'); + const meta = checker.getComponentMeta(componentPath); + + expect(meta.type).toEqual(TypeMeta.Function); + + expect(meta.slots.find(slot => + slot.name === 'default' + && slot.type === '{ foo: number; }' + )).toBeDefined(); + }); + test('template-slots without a script block', () => { const componentPath = path.resolve(__dirname, '../../../test-workspace/component-meta/template-slots/component-no-script.vue'); const meta = checker.getComponentMeta(componentPath); diff --git a/packages/component-type-helpers/index.d.ts b/packages/component-type-helpers/index.d.ts index 0ce45dcf0d..033e56ce51 100644 --- a/packages/component-type-helpers/index.d.ts +++ b/packages/component-type-helpers/index.d.ts @@ -14,12 +14,12 @@ export type ComponentProps = export type ComponentSlots = T extends new () => { $slots: infer S; } ? NonNullable : - T extends (props: any, ctx: { slots: infer S; }, ...args: any) => any ? NonNullable : + T extends (props: any, ctx: { slots: infer S; attrs: any; emit: any; }, ...args: any) => any ? NonNullable : {}; export type ComponentEmit = T extends new () => { $emit: infer E; } ? NonNullable : - T extends (props: any, ctx: { emit: infer E; }, ...args: any) => any ? NonNullable : + T extends (props: any, ctx: { slots: any; attrs: any; emit: infer E; }, ...args: any) => any ? NonNullable : {}; export type ComponentExposed = diff --git a/packages/component-type-helpers/index.js b/packages/component-type-helpers/index.js index 49123c5d9c..90132268f3 100644 --- a/packages/component-type-helpers/index.js +++ b/packages/component-type-helpers/index.js @@ -13,12 +13,12 @@ export type ComponentProps = export type ComponentSlots = T extends new () => { $slots: infer S; } ? NonNullable : - T extends (props: any, ctx: { slots: infer S; }, ...args: any) => any ? NonNullable : + T extends (props: any, ctx: { slots: infer S; attrs: any; emit: any; }, ...args: any) => any ? NonNullable : {}; export type ComponentEmit = T extends new () => { $emit: infer E; } ? NonNullable : - T extends (props: any, ctx: { emit: infer E; }, ...args: any) => any ? NonNullable : + T extends (props: any, ctx: { slots: any; attrs: any; emit: infer E; }, ...args: any) => any ? NonNullable : {}; export type ComponentExposed = diff --git a/packages/tsc/tests/__snapshots__/dts.spec.ts.snap b/packages/tsc/tests/__snapshots__/dts.spec.ts.snap index 8c6ae2bc13..2ffcb71db3 100644 --- a/packages/tsc/tests/__snapshots__/dts.spec.ts.snap +++ b/packages/tsc/tests/__snapshots__/dts.spec.ts.snap @@ -22,6 +22,59 @@ export default _default; " `; +exports[`vue-tsc-dts > Input: generic/component.vue, Output: generic/component.vue.d.ts 1`] = ` +"declare const _default: (__VLS_props: { + onBar?: (data: number) => any; + foo: number; +} & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, __VLS_ctx?: { + attrs: any; + emit: (e: 'bar', data: number) => void; + slots: Readonly<{ + default?(data: { + foo: number; + }): any; + }>; +}, __VLS_expose?: (exposed: import("vue").ShallowUnwrapRef<{ + baz: number; +}>) => void, __VLS_setup?: Promise<{ + props: { + onBar?: (data: number) => any; + foo: number; + } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps; + expose(exposed: import("vue").ShallowUnwrapRef<{ + baz: number; + }>): void; + attrs: any; + slots: Readonly<{ + default?(data: { + foo: number; + }): any; + }>; + emit: (e: 'bar', data: number) => void; +}>) => import("vue").VNode & { + __ctx?: { + props: { + onBar?: (data: number) => any; + foo: number; + } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps; + expose(exposed: import("vue").ShallowUnwrapRef<{ + baz: number; + }>): void; + attrs: any; + slots: Readonly<{ + default?(data: { + foo: number; + }): any; + }>; + emit: (e: 'bar', data: number) => void; + }; +}; +export default _default; +" +`; + exports[`vue-tsc-dts > Input: non-component/component.ts, Output: non-component/component.d.ts 1`] = ` "declare const _default: {}; export default _default; diff --git a/test-workspace/component-meta/generic/component.vue b/test-workspace/component-meta/generic/component.vue new file mode 100644 index 0000000000..39664c35ac --- /dev/null +++ b/test-workspace/component-meta/generic/component.vue @@ -0,0 +1,6 @@ +