Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: inherit emits props #3533

Merged
merged 14 commits into from
Sep 25, 2023
56 changes: 39 additions & 17 deletions packages/vue-language-core/src/generators/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function generate(
const bypassDefineComponent = lang === 'js' || lang === 'jsx';
const usedHelperTypes = {
DefinePropsToOptions: false,
mergePropDefaults: false,
MergePropDefaults: false,
WithTemplateSlots: false,
PropsChildren: false,
};
Expand Down Expand Up @@ -119,7 +119,7 @@ export function generate(
codes.push(`type __VLS_TypePropsToRuntimeProps<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? { type: import('${vueCompilerOptions.lib}').PropType<__VLS_NonUndefinedable<T[K]>> } : { type: import('${vueCompilerOptions.lib}').PropType<T[K]>, required: true } };\n`);
}
}
if (usedHelperTypes.mergePropDefaults) {
if (usedHelperTypes.MergePropDefaults) {
codes.push(`type __VLS_WithDefaults<P, D> = {
// use 'keyof Pick<P, keyof P>' instead of 'keyof P' to keep props jsdoc
[K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
Expand Down Expand Up @@ -293,18 +293,29 @@ export function generate(
}
codes.push(`>`);
codes.push('(\n');
codes.push(
`__VLS_props: Awaited<typeof __VLS_setup>['props']`,
`& import('${vueCompilerOptions.lib}').VNodeProps`,
`& import('${vueCompilerOptions.lib}').AllowedComponentProps`,
`& import('${vueCompilerOptions.lib}').ComponentCustomProps,\n`,
);
codes.push(`__VLS_ctx?: Pick<Awaited<typeof __VLS_setup>, 'attrs' | 'emit' | 'slots'>,\n`);
codes.push(`__VLS_props: Awaited<typeof __VLS_setup>['props'],\n`);
codes.push(`__VLS_ctx?: __VLS_Prettify<Pick<Awaited<typeof __VLS_setup>, 'attrs' | 'emit' | 'slots'>>,\n`); // use __VLS_Prettify for less dts code
codes.push(`__VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>['expose'],\n`);
codes.push('__VLS_setup = (async () => {\n');
scriptSetupGeneratedOffset = generateSetupFunction(true, 'none', definePropMirrors);

//#region props
codes.push(`const __VLS_fnComponent = `);
codes.push(`(await import('${vueCompilerOptions.lib}')).defineComponent({\n`);
if (scriptSetupRanges.propsRuntimeArg) {
codes.push(`props: `);
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.propsRuntimeArg.start, scriptSetupRanges.propsRuntimeArg.end);
codes.push(`,\n`);

}
if (scriptSetupRanges.defineEmits) {
codes.push(
`emits: ({} as __VLS_NormalizeEmits<typeof `,
scriptSetupRanges.emitsAssignName ?? '__VLS_emit',
`>),\n`,
);
}
codes.push(`});\n`);
if (scriptSetupRanges.defineProp.length) {
codes.push(`const __VLS_defaults = {\n`);
for (const defineProp of scriptSetupRanges.defineProp) {
Expand All @@ -322,10 +333,7 @@ export function generate(
}
codes.push(`};\n`);
}
codes.push(`let __VLS_props!: {}`);
if (scriptSetupRanges.propsRuntimeArg) {
codes.push(` & InstanceType<typeof __VLS_internalComponent>['$props']`);
}
codes.push(`let __VLS_fnPropsTypeOnly!: {}`); // TODO: reuse __VLS_fnPropsTypeOnly even without generic, and remove __VLS_propsOption_defineProp
if (scriptSetupRanges.propsTypeArg) {
codes.push(` & `);
addVirtualCode('scriptSetup', scriptSetupRanges.propsTypeArg.start, scriptSetupRanges.propsTypeArg.end);
Expand Down Expand Up @@ -355,15 +363,29 @@ export function generate(
}
codes.push(`}`);
}
codes.push(`;\n`);
codes.push(`let __VLS_fnPropsDefineComponent!: InstanceType<typeof __VLS_fnComponent>['$props']`);
codes.push(`;\n`);
codes.push(`let __VLS_fnPropsSlots!: `);
if (scriptSetupRanges.defineSlots && vueCompilerOptions.jsxSlots) {
usedHelperTypes.PropsChildren = true;
codes.push(` & __VLS_PropsChildren<typeof __VLS_slots>`);
codes.push(`__VLS_PropsChildren<typeof __VLS_slots>`);
}
else {
codes.push(`{}`);
}
codes.push(`;\n`);
codes.push(
`let __VLS_defaultProps!: `,
`import('${vueCompilerOptions.lib}').VNodeProps`,
`& import('${vueCompilerOptions.lib}').AllowedComponentProps`,
`& import('${vueCompilerOptions.lib}').ComponentCustomProps`,
`;\n`,
);
//#endregion

codes.push('return {} as {\n');
codes.push(`props: typeof __VLS_props,\n`);
codes.push(`props: __VLS_Prettify<Omit<typeof __VLS_fnPropsDefineComponent & typeof __VLS_fnPropsTypeOnly, keyof typeof __VLS_defaultProps>> & typeof __VLS_fnPropsSlots & typeof __VLS_defaultProps,\n`);
codes.push(`expose(exposed: ${scriptSetupRanges.exposeRuntimeArg ? 'typeof __VLS_exposed' : '{}'}): void,\n`);
codes.push('attrs: any,\n');
codes.push('slots: ReturnType<typeof __VLS_template>,\n');
Expand Down Expand Up @@ -596,13 +618,13 @@ declare function defineProp<T>(value?: T | (() => T), required?: boolean, rest?:
codes.push('...{} as ');

if (scriptSetupRanges.withDefaultsArg) {
usedHelperTypes.mergePropDefaults = true;
usedHelperTypes.MergePropDefaults = true;
codes.push(`__VLS_WithDefaults<`);
}

codes.push(`__VLS_TypePropsToRuntimeProps<`);
if (functional) {
codes.push(`typeof __VLS_props`);
codes.push(`typeof __VLS_fnPropsTypeOnly`);
}
else {
addExtraReferenceVirtualCode('scriptSetup', scriptSetupRanges.propsTypeArg.start, scriptSetupRanges.propsTypeArg.end);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script setup lang="tsx" generic="T">
defineEmits<{
(name: 'foo', value: string): void
}>();
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { exactType } from 'vue-tsc/shared';
import Comp from './Comp.vue';

<Comp onFoo={s => exactType(s, '' as string)} />;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script setup lang="ts" generic="T">
type Emits = {
(name: 'update:modelValue', modelValue: string): void
(name: 'removeOptions', options: number): void
(name: 'addOptions', options: number): void
(name: 'selectOptions', options: number): void
(name: 'clickNode', option: number): void
};

defineEmits<Emits>();
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script lang="ts" setup>
import { exactType } from 'vue-tsc/shared';
import Comp from './Comp.vue';
</script>

<template>
<Comp @update:modelValue="s => exactType(s, '' as string)"></Comp>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script setup lang="ts" generic="T extends number">
defineEmits<{
(e: 'myEvent', data: T): void;
}>()
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script setup lang="ts">
import { exactType } from 'vue-tsc/shared';
import Comp from './Comp.vue';
</script>

<template>
<Comp @my-event="v => exactType(v, 1 as number)" />
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,14 @@ const ScriptSetupDefaultPropsExact = defineComponent({
});
// vue 3.3 generic
declare const ScriptSetupGenericExact: <T, >(
_props: NonNullable<Awaited<typeof _setup>>['props'] & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps,
_props: NonNullable<Awaited<typeof _setup>>['props'],
_ctx?: Pick<NonNullable<Awaited<typeof _setup>>, 'attrs' | 'emit' | 'slots'>,
_expose?: NonNullable<Awaited<typeof _setup>>['expose'],
_setup?: Promise<{
props: { foo: T; } & { [K in keyof JSX.ElementChildrenAttribute]?: Readonly<{ default?(data: T): any; }> },
props: { $children?: Readonly<{ default?(data: T): any; }>; } & {
onBar?: ((data: T) => any) | undefined;
foo: T;
} & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps,
attrs: any,
slots: Readonly<{ default?(data: T): any; }>,
emit: { (e: 'bar', data: T): void; },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ import ScriptSetupGeneric from './script-setup-generic.vue';
const ScriptSetupExact = defineComponent({
props: {} as {
a: PropType<string>;
b: { type: PropType<string>, required: true };
c: { type: PropType<number>, required: true };
b: { type: PropType<string>, required: true; };
c: { type: PropType<number>, required: true; };
d: PropType<number>;
e: PropType<string>;
f: { type: PropType<string>, required: true };
f: { type: PropType<string>, required: true; };
g: PropType<string>;
},
setup() {
return {};
},
});
declare const ScriptSetupGenericExact: <T, >(
_props: NonNullable<Awaited<typeof _setup>>['props'] & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps,
_props: NonNullable<Awaited<typeof _setup>>['props'],
_ctx?: Pick<NonNullable<Awaited<typeof _setup>>, 'attrs' | 'emit' | 'slots'>,
_expose?: NonNullable<Awaited<typeof _setup>>['expose'],
_setup?: Promise<{
Expand All @@ -28,13 +28,13 @@ declare const ScriptSetupGenericExact: <T, >(
b?: T | undefined;
c?: T | undefined;
d: T;
},
} & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps,
attrs: any,
slots: {},
emit: any,
expose(_exposed: {}): void,
}>
) => import('vue').VNode & { __ctx?: Awaited<typeof _setup> };
) => import('vue').VNode & { __ctx?: Awaited<typeof _setup>; };

exactType(ScriptSetup, ScriptSetupExact);
exactType(ScriptSetupGeneric, ScriptSetupGenericExact);
Expand Down
80 changes: 51 additions & 29 deletions packages/vue-tsc/tests/__snapshots__/dts.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -86,25 +86,21 @@ export default _default;

exports[`vue-tsc-dts > Input: components/script-setup-generic.vue, Output: components/script-setup-generic.vue.d.ts 1`] = `
"declare const _default: <T>(__VLS_props: {
onBar?: (data: T) => any;
foo: T;
} & import(\\"vue\\").VNodeProps & import(\\"vue\\").AllowedComponentProps & import(\\"vue\\").ComponentCustomProps, __VLS_ctx?: Pick<{
props: {
foo: T;
};
expose(exposed: {
baz: T;
}): void;
attrs: any;
} & import(\\"vue\\").VNodeProps & import(\\"vue\\").AllowedComponentProps & import(\\"vue\\").ComponentCustomProps, __VLS_ctx?: {
slots: Readonly<{
default?(data: T): any;
}>;
attrs: any;
emit: (e: 'bar', data: T) => void;
}, \\"slots\\" | \\"attrs\\" | \\"emit\\">, __VLS_expose?: (exposed: {
}, __VLS_expose?: (exposed: {
baz: T;
}) => void, __VLS_setup?: Promise<{
props: {
onBar?: (data: T) => any;
foo: T;
};
} & import(\\"vue\\").VNodeProps & import(\\"vue\\").AllowedComponentProps & import(\\"vue\\").ComponentCustomProps;
expose(exposed: {
baz: T;
}): void;
Expand All @@ -118,8 +114,9 @@ exports[`vue-tsc-dts > Input: components/script-setup-generic.vue, Output: compo
}> & {
__ctx?: {
props: {
onBar?: (data: T) => any;
foo: T;
};
} & import(\\"vue\\").VNodeProps & import(\\"vue\\").AllowedComponentProps & import(\\"vue\\").ComponentCustomProps;
expose(exposed: {
baz: T;
}): void;
Expand Down Expand Up @@ -289,28 +286,21 @@ export default _default;

exports[`vue-tsc-dts > Input: defineProp_B/script-setup-generic.vue, Output: defineProp_B/script-setup-generic.vue.d.ts 1`] = `
"declare const _default: <T>(__VLS_props: {
a?: T;
b?: T;
c?: T;
d: T;
} & import(\\"vue\\").VNodeProps & import(\\"vue\\").AllowedComponentProps & import(\\"vue\\").ComponentCustomProps, __VLS_ctx?: Pick<{
props: {
a?: T;
b?: T;
c?: T;
d: T;
};
expose(exposed: {}): void;
attrs: any;
a?: T;
b?: T;
} & import(\\"vue\\").VNodeProps & import(\\"vue\\").AllowedComponentProps & import(\\"vue\\").ComponentCustomProps, __VLS_ctx?: {
slots: {};
attrs: any;
emit: any;
}, \\"slots\\" | \\"attrs\\" | \\"emit\\">, __VLS_expose?: (exposed: {}) => void, __VLS_setup?: Promise<{
}, __VLS_expose?: (exposed: {}) => void, __VLS_setup?: Promise<{
props: {
a?: T;
b?: T;
c?: T;
d: T;
};
a?: T;
b?: T;
} & import(\\"vue\\").VNodeProps & import(\\"vue\\").AllowedComponentProps & import(\\"vue\\").ComponentCustomProps;
expose(exposed: {}): void;
attrs: any;
slots: {};
Expand All @@ -320,11 +310,11 @@ exports[`vue-tsc-dts > Input: defineProp_B/script-setup-generic.vue, Output: def
}> & {
__ctx?: {
props: {
a?: T;
b?: T;
c?: T;
d: T;
};
a?: T;
b?: T;
} & import(\\"vue\\").VNodeProps & import(\\"vue\\").AllowedComponentProps & import(\\"vue\\").ComponentCustomProps;
expose(exposed: {}): void;
attrs: any;
slots: {};
Expand All @@ -347,6 +337,38 @@ export default _default;
"
`;

exports[`vue-tsc-dts > Input: generic-interface/main.vue, Output: generic-interface/main.vue.d.ts 1`] = `
"declare const _default: <T>(__VLS_props: {
foo: T;
} & import(\\"vue\\").VNodeProps & import(\\"vue\\").AllowedComponentProps & import(\\"vue\\").ComponentCustomProps, __VLS_ctx?: {
slots: {};
attrs: any;
emit: any;
}, __VLS_expose?: (exposed: {}) => void, __VLS_setup?: Promise<{
props: {
foo: T;
} & import(\\"vue\\").VNodeProps & import(\\"vue\\").AllowedComponentProps & import(\\"vue\\").ComponentCustomProps;
expose(exposed: {}): void;
attrs: any;
slots: {};
emit: any;
}>) => import(\\"vue\\").VNode<import(\\"vue\\").RendererNode, import(\\"vue\\").RendererElement, {
[key: string]: any;
}> & {
__ctx?: {
props: {
foo: T;
} & import(\\"vue\\").VNodeProps & import(\\"vue\\").AllowedComponentProps & import(\\"vue\\").ComponentCustomProps;
expose(exposed: {}): void;
attrs: any;
slots: {};
emit: any;
};
};
export default _default;
"
`;

exports[`vue-tsc-dts > Input: slots/main.vue, Output: slots/main.vue.d.ts 1`] = `
"declare const _default: __VLS_WithTemplateSlots<import(\\"vue\\").DefineComponent<{}, {}, {}, {}, {}, import(\\"vue\\").ComponentOptionsMixin, import(\\"vue\\").ComponentOptionsMixin, {}, string, import(\\"vue\\").VNodeProps & import(\\"vue\\").AllowedComponentProps & import(\\"vue\\").ComponentCustomProps, Readonly<import(\\"vue\\").ExtractPropTypes<{}>>, {}, {}>, Partial<Record<\\"baz\\", (_: {
str: string;
Expand Down