Skip to content

Commit

Permalink
types(runtime-core): provide valid type for default $emit (#1498)
Browse files Browse the repository at this point in the history
  • Loading branch information
pikax authored Jul 8, 2020
1 parent f0394e2 commit 1e90605
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 11 deletions.
2 changes: 1 addition & 1 deletion packages/runtime-core/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 9 additions & 7 deletions packages/runtime-core/src/componentEmits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 3 additions & 2 deletions packages/runtime-core/src/h.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
16 changes: 15 additions & 1 deletion test-dts/defineComponent.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
reactive,
createApp,
expectError,
expectType
expectType,
ComponentPublicInstance
} from './index'

describe('with object props', () => {
Expand Down Expand Up @@ -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')
})

0 comments on commit 1e90605

Please sign in to comment.