Skip to content

Commit

Permalink
fix: inherit emits props (#3533)
Browse files Browse the repository at this point in the history
Co-authored-by: Johnson Chu <[email protected]>
  • Loading branch information
so1ve and johnsoncodehk authored Sep 25, 2023
1 parent c153572 commit f043b32
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 54 deletions.
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

0 comments on commit f043b32

Please sign in to comment.