diff --git a/types/test/v3/define-component-test.tsx b/types/test/v3/define-component-test.tsx index 7e6d1968ca3..64a80941881 100644 --- a/types/test/v3/define-component-test.tsx +++ b/types/test/v3/define-component-test.tsx @@ -966,6 +966,16 @@ describe('emits', () => { } } }) + + // should have `onXXX` props for emits + defineComponent({ + emits: { + foo: (n: number) => n > 0 + }, + setup(props) { + expectType<((n: number) => boolean) | undefined>(props.onFoo) + } + }) }) // describe('componentOptions setup should be `SetupContext`', () => { diff --git a/types/v3-component-options.d.ts b/types/v3-component-options.d.ts index e2da34e753f..818789ffe60 100644 --- a/types/v3-component-options.d.ts +++ b/types/v3-component-options.d.ts @@ -1,7 +1,7 @@ import { Vue } from './vue' import { VNode } from './vnode' import { ComponentOptions as Vue2ComponentOptions } from './options' -import { EmitsOptions, SetupContext } from './v3-setup-context' +import { EmitsOptions, EmitsToProps, SetupContext } from './v3-setup-context' import { Data, LooseRequired, UnionToIntersection } from './common' import { ComponentPropsOptions, @@ -137,6 +137,13 @@ export type ExtractComputedReturns = { : never } +export type ResolveProps = Readonly< + PropsOrPropOptions extends ComponentPropsOptions + ? ExtractPropTypes + : PropsOrPropOptions +> & + ({} extends E ? {} : EmitsToProps) + export type ComponentOptionsWithProps< PropsOptions = ComponentPropsOptions, RawBindings = Data, @@ -147,7 +154,7 @@ export type ComponentOptionsWithProps< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, Emits extends EmitsOptions = {}, EmitsNames extends string = string, - Props = ExtractPropTypes, + Props = ResolveProps, Defaults = ExtractDefaultPropTypes > = ComponentOptionsBase< Props, @@ -185,7 +192,7 @@ export type ComponentOptionsWithArrayProps< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, Emits extends EmitsOptions = {}, EmitsNames extends string = string, - Props = Readonly<{ [key in PropNames]?: any }> + Props = Readonly<{ [key in PropNames]?: any }> & EmitsToProps > = ComponentOptionsBase< Props, RawBindings, @@ -221,9 +228,10 @@ export type ComponentOptionsWithoutProps< Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, Emits extends EmitsOptions = {}, - EmitsNames extends string = string + EmitsNames extends string = string, + PropsWithEmits = Props & EmitsToProps > = ComponentOptionsBase< - Props, + PropsWithEmits, RawBindings, D, C, diff --git a/types/v3-define-component.d.ts b/types/v3-define-component.d.ts index 03ef52d1856..ed2f6fdceba 100644 --- a/types/v3-define-component.d.ts +++ b/types/v3-define-component.d.ts @@ -10,7 +10,8 @@ import { ComponentOptionsWithArrayProps, ComponentOptionsWithProps, ComponentOptionsMixin, - ComponentOptionsBase + ComponentOptionsBase, + ResolveProps } from './v3-component-options' import { ComponentPublicInstanceConstructor, @@ -161,7 +162,7 @@ export function defineComponent< Extends, Emits, EmitsNames, - Props + ResolveProps > : { functional?: never } & ComponentOptionsWithProps< PropsOptions, diff --git a/types/v3-setup-context.d.ts b/types/v3-setup-context.d.ts index 77b49bed8a6..f6bee6431b8 100644 --- a/types/v3-setup-context.d.ts +++ b/types/v3-setup-context.d.ts @@ -13,6 +13,25 @@ export type ObjectEmitsOptions = Record< export type EmitsOptions = ObjectEmitsOptions | string[] +export type EmitsToProps = T extends string[] + ? { + [K in string & `on${Capitalize}`]?: (...args: any[]) => any + } + : T extends ObjectEmitsOptions + ? { + [K in string & + `on${Capitalize}`]?: K extends `on${infer C}` + ? T[Uncapitalize] extends null + ? (...args: any[]) => any + : ( + ...args: T[Uncapitalize] extends (...args: infer P) => any + ? P + : never + ) => any + : never + } + : {} + export type EmitFn< Options = ObjectEmitsOptions, Event extends keyof Options = keyof Options,