From bdec2f668f7bf47f131b8c1c2a385fd091e65570 Mon Sep 17 00:00:00 2001 From: pikax Date: Fri, 3 Jul 2020 11:10:47 +0100 Subject: [PATCH 1/4] types(runtime-core): provide valid type for `$emit` when used with `ComponentPublicInstance` --- packages/runtime-core/src/componentEmits.ts | 16 +++++++++------- test-dts/defineComponent.test-d.tsx | 16 +++++++++++++++- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/runtime-core/src/componentEmits.ts b/packages/runtime-core/src/componentEmits.ts index 7bb20f73e2e..69298112f67 100644 --- a/packages/runtime-core/src/componentEmits.ts +++ b/packages/runtime-core/src/componentEmits.ts @@ -25,13 +25,15 @@ export type EmitFn< Event extends keyof Options = keyof Options > = Options extends any[] ? (event: Options[0], ...args: any[]) => void - : UnionToIntersection< - { - [key in Event]: Options[key] extends ((...args: infer Args) => any) - ? (event: key, ...args: Args) => void - : (event: key, ...args: any[]) => void - }[Event] - > + : {} extends Options // if the emit is empty object (usually the default value for emit) should be converted to function + ? (event: string, ...args: any[]) => void + : UnionToIntersection< + { + [key in Event]: Options[key] extends ((...args: infer Args) => any) + ? (event: key, ...args: Args) => void + : (event: key, ...args: any[]) => void + }[Event] + > export function emit( instance: ComponentInternalInstance, diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index bc1e5f98e54..eaa6691523f 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -6,7 +6,8 @@ import { reactive, createApp, expectError, - expectType + expectType, + ComponentPublicInstance } from './index' describe('with object props', () => { @@ -669,4 +670,17 @@ describe('emits', () => { expectError(this.$emit('nope')) } }) + + // without emits + defineComponent({ + setup(props, { emit }) { + emit('test', 1) + emit('test') + } + }) + + // emit should be valid when ComponentPublicInstance is used. + const instance: ComponentPublicInstance = {} as any + instance.$emit('test', 1) + instance.$emit('test') }) From bd014c0a085a4819de58c7830f9f919136b220aa Mon Sep 17 00:00:00 2001 From: pikax Date: Fri, 3 Jul 2020 11:36:14 +0100 Subject: [PATCH 2/4] fix functionalComponent options --- packages/runtime-core/src/component.ts | 2 +- packages/runtime-core/src/h.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 312c583ff4a..211ffb8575a 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -79,7 +79,7 @@ export interface ComponentInternalOptions { export interface FunctionalComponent< P = {}, - E extends EmitsOptions = Record + E extends EmitsOptions = {} > extends ComponentInternalOptions { // use of any here is intentional so it can be a valid JSX Element constructor (props: P, ctx: SetupContext): any diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index 2b5d8c54e15..f81a3cc66be 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -12,6 +12,7 @@ import { isObject, isArray } from '@vue/shared' import { RawSlots } from './componentSlots' import { FunctionalComponent, Component } from './component' import { ComponentOptions } from './componentOptions' +import { EmitsOptions } from './componentEmits' // `h` is a more user-friendly version of `createVNode` that allows omitting the // props when possible. It is intended for manually written render functions. @@ -107,8 +108,8 @@ export function h( ): VNode // functional component -export function h

( - type: FunctionalComponent

, +export function h( + type: FunctionalComponent, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots ): VNode From 1df901151e83264c51f0999990d1d0d75c4e6591 Mon Sep 17 00:00:00 2001 From: pikax Date: Fri, 3 Jul 2020 11:40:08 +0100 Subject: [PATCH 3/4] use empty object as value --- packages/runtime-core/src/h.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index f81a3cc66be..a00e465bdf7 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -108,7 +108,7 @@ export function h( ): VNode // functional component -export function h( +export function h( type: FunctionalComponent, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots From 56ff6c13f27cfdea843e744d77067d12fc042fdf Mon Sep 17 00:00:00 2001 From: pikax Date: Fri, 3 Jul 2020 15:53:58 +0100 Subject: [PATCH 4/4] remove as any --- test-dts/defineComponent.test-d.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-dts/defineComponent.test-d.tsx b/test-dts/defineComponent.test-d.tsx index eaa6691523f..009ddbf5414 100644 --- a/test-dts/defineComponent.test-d.tsx +++ b/test-dts/defineComponent.test-d.tsx @@ -680,7 +680,7 @@ describe('emits', () => { }) // emit should be valid when ComponentPublicInstance is used. - const instance: ComponentPublicInstance = {} as any + const instance = {} as ComponentPublicInstance instance.$emit('test', 1) instance.$emit('test') })