]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
types(runtime-core): provide valid type for default `$emit` (#1498)
authorCarlos Rodrigues <david-181@hotmail.com>
Wed, 8 Jul 2020 15:51:03 +0000 (16:51 +0100)
committerGitHub <noreply@github.com>
Wed, 8 Jul 2020 15:51:03 +0000 (11:51 -0400)
packages/runtime-core/src/component.ts
packages/runtime-core/src/componentEmits.ts
packages/runtime-core/src/h.ts
test-dts/defineComponent.test-d.tsx

index 312c583ff4a296ce2c2b0c9c20a20b606776160c..211ffb8575a28e6a117d8e0de9bcddfa10307f5f 100644 (file)
@@ -79,7 +79,7 @@ export interface ComponentInternalOptions {
 
 export interface FunctionalComponent<
   P = {},
-  E extends EmitsOptions = Record<string, any>
+  E extends EmitsOptions = {}
 > extends ComponentInternalOptions {
   // use of any here is intentional so it can be a valid JSX Element constructor
   (props: P, ctx: SetupContext<E>): any
index 7bb20f73e2e94575e7eb80976de9269fa44368a5..69298112f677566a4638417f5e54ff63e21e4e4e 100644 (file)
@@ -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,
index 2b5d8c54e15ac87b63153db76ff4597361578ab8..a00e465bdf799f6320a73491d7fdff68b5be0770 100644 (file)
@@ -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<P>(
-  type: FunctionalComponent<P>,
+export function h<P, E extends EmitsOptions = {}>(
+  type: FunctionalComponent<P, E>,
   props?: (RawProps & P) | ({} extends P ? null : never),
   children?: RawChildren | RawSlots
 ): VNode
index bc1e5f98e54ebd74c782f16816a3874eb7b8e869..009ddbf5414f0abf403137a80cb1f9f8e3af791c 100644 (file)
@@ -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 = {} as ComponentPublicInstance
+  instance.$emit('test', 1)
+  instance.$emit('test')
 })