Skip to content

Commit b980175

Browse files
authored
feat: add component $emit typing support (#846)
1 parent 0fbc572 commit b980175

14 files changed

+1327
-774
lines changed

src/apis/createApp.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type Vue from 'vue'
2-
import { VueConstructor } from 'vue/types/umd'
2+
import { VueConstructor } from 'vue'
33
import { getVueConstructor } from '../runtimeContext'
44
import { warn } from '../utils'
55

src/apis/createElement.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import Vue from 'vue'
1+
import type { CreateElement } from 'vue'
22
import { getVueConstructor, getCurrentInstance } from '../runtimeContext'
33
import { defineComponentInstance } from '../utils/helper'
44
import { warn } from '../utils'
55

6-
type CreateElement = Vue['$createElement']
7-
86
let fallbackCreateElement: CreateElement
97

108
export const createElement = function createElement(...args: any) {

src/component/componentOptions.ts

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Vue, { VNode, ComponentOptions as Vue2ComponentOptions } from 'vue'
2-
import { SetupContext } from '../runtimeContext'
2+
import { EmitsOptions, SetupContext } from '../runtimeContext'
33
import { Data } from './common'
44
import { ComponentPropsOptions, ExtractPropTypes } from './componentProps'
55
import { ComponentRenderProxy } from './componentProxy'
@@ -8,13 +8,6 @@ export { ComponentPropsOptions } from './componentProps'
88
export type ComputedGetter<T> = (ctx?: any) => T
99
export type ComputedSetter<T> = (v: T) => void
1010

11-
export type ObjectEmitsOptions = Record<
12-
string,
13-
((...args: any[]) => any) | null
14-
>
15-
16-
export type EmitsOptions = ObjectEmitsOptions | string[]
17-
1811
export interface WritableComputedOptions<T> {
1912
get: ComputedGetter<T>
2013
set: ComputedSetter<T>
@@ -39,7 +32,10 @@ interface ComponentOptionsBase<
3932
Props,
4033
D = Data,
4134
C extends ComputedOptions = {},
42-
M extends MethodOptions = {}
35+
M extends MethodOptions = {},
36+
Mixin = {},
37+
Extends = {},
38+
Emits extends EmitsOptions = {}
4339
> extends Omit<
4440
Vue2ComponentOptions<Vue, D, M, C, Props>,
4541
'data' | 'computed' | 'method' | 'setup' | 'props'
@@ -67,37 +63,52 @@ export type ComponentOptionsWithProps<
6763
D = Data,
6864
C extends ComputedOptions = {},
6965
M extends MethodOptions = {},
66+
Mixin = {},
67+
Extends = {},
68+
Emits extends EmitsOptions = {},
7069
Props = ExtractPropTypes<PropsOptions>
7170
> = ComponentOptionsBase<Props, D, C, M> & {
7271
props?: PropsOptions
73-
emits?: (EmitsOptions | string[]) & ThisType<void>
72+
emits?: Emits & ThisType<void>
7473
setup?: SetupFunction<Props, RawBindings>
75-
} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>>
74+
} & ThisType<
75+
ComponentRenderProxy<Props, RawBindings, D, C, M, Mixin, Extends, Emits>
76+
>
7677

7778
export type ComponentOptionsWithArrayProps<
7879
PropNames extends string = string,
7980
RawBindings = Data,
8081
D = Data,
8182
C extends ComputedOptions = {},
8283
M extends MethodOptions = {},
84+
Mixin = {},
85+
Extends = {},
86+
Emits extends EmitsOptions = {},
8387
Props = Readonly<{ [key in PropNames]?: any }>
8488
> = ComponentOptionsBase<Props, D, C, M> & {
8589
props?: PropNames[]
86-
emits?: (EmitsOptions | string[]) & ThisType<void>
90+
emits?: Emits & ThisType<void>
8791
setup?: SetupFunction<Props, RawBindings>
88-
} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>>
92+
} & ThisType<
93+
ComponentRenderProxy<Props, RawBindings, D, C, M, Mixin, Extends, Emits>
94+
>
8995

9096
export type ComponentOptionsWithoutProps<
9197
Props = {},
9298
RawBindings = Data,
9399
D = Data,
94100
C extends ComputedOptions = {},
95-
M extends MethodOptions = {}
101+
M extends MethodOptions = {},
102+
Mixin = {},
103+
Extends = {},
104+
Emits extends EmitsOptions = {}
96105
> = ComponentOptionsBase<Props, D, C, M> & {
97106
props?: undefined
98-
emits?: (EmitsOptions | string[]) & ThisType<void>
107+
emits?: Emits & ThisType<void>
99108
setup?: SetupFunction<Props, RawBindings>
100-
} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>>
109+
} & ThisType<
110+
ComponentRenderProxy<Props, RawBindings, D, C, M, Mixin, Extends, Emits>
111+
>
101112

102113
export type WithLegacyAPI<T, D, C, M, Props> = T &
103114
Omit<Vue2ComponentOptions<Vue, D, M, C, Props>, keyof T>

src/component/componentProxy.ts

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,29 @@ import {
2121
ComponentInternalInstance,
2222
EmitFn,
2323
EmitsOptions,
24+
ObjectEmitsOptions,
2425
Slots,
2526
} from '../runtimeContext'
2627

28+
type EmitsToProps<T extends EmitsOptions> = T extends string[]
29+
? {
30+
[K in string & `on${Capitalize<T[number]>}`]?: (...args: any[]) => any
31+
}
32+
: T extends ObjectEmitsOptions
33+
? {
34+
[K in string &
35+
`on${Capitalize<string & keyof T>}`]?: K extends `on${infer C}`
36+
? T[Uncapitalize<C>] extends null
37+
? (...args: any[]) => any
38+
: (
39+
...args: T[Uncapitalize<C>] extends (...args: infer P) => any
40+
? P
41+
: never
42+
) => any
43+
: never
44+
}
45+
: {}
46+
2747
export type ComponentInstance = InstanceType<VueConstructor>
2848

2949
// public properties exposed on the proxy, which is used as the render context
@@ -34,6 +54,9 @@ export type ComponentRenderProxy<
3454
D = {}, // return from data()
3555
C extends ComputedOptions = {},
3656
M extends MethodOptions = {},
57+
Mixin = {},
58+
Extends = {},
59+
Emits extends EmitsOptions = {},
3760
PublicProps = P,
3861
Defaults = {},
3962
MakeDefaultsOptional extends boolean = false
@@ -45,28 +68,37 @@ export type ComponentRenderProxy<
4568
: P & PublicProps
4669
>
4770
$attrs: Data
71+
$emit: EmitFn<Emits>
4872
} & Readonly<P> &
4973
ShallowUnwrapRef<B> &
5074
D &
5175
M &
5276
ExtractComputedReturns<C> &
53-
Omit<Vue, '$data' | '$props' | '$attrs'>
77+
Omit<Vue, '$data' | '$props' | '$attrs' | '$emit'>
5478

5579
// for Vetur and TSX support
5680
type VueConstructorProxy<
5781
PropsOptions,
5882
RawBindings,
5983
Data,
6084
Computed extends ComputedOptions,
61-
Methods extends MethodOptions
62-
> = VueConstructor & {
85+
Methods extends MethodOptions,
86+
Mixin = {},
87+
Extends = {},
88+
Emits extends EmitsOptions = {},
89+
Props = ExtractPropTypes<PropsOptions> &
90+
({} extends Emits ? {} : EmitsToProps<Emits>)
91+
> = Omit<VueConstructor, never> & {
6392
new (...args: any[]): ComponentRenderProxy<
64-
ExtractPropTypes<PropsOptions>,
93+
Props,
6594
ShallowUnwrapRef<RawBindings>,
6695
Data,
6796
Computed,
6897
Methods,
69-
ExtractPropTypes<PropsOptions>,
98+
Mixin,
99+
Extends,
100+
Emits,
101+
Props,
70102
ExtractDefaultPropTypes<PropsOptions>,
71103
true
72104
>
@@ -81,7 +113,10 @@ export type VueProxy<
81113
RawBindings,
82114
Data = DefaultData<Vue>,
83115
Computed extends ComputedOptions = DefaultComputed,
84-
Methods extends MethodOptions = DefaultMethods<Vue>
116+
Methods extends MethodOptions = DefaultMethods<Vue>,
117+
Mixin = {},
118+
Extends = {},
119+
Emits extends EmitsOptions = {}
85120
> = Vue2ComponentOptions<
86121
Vue,
87122
ShallowUnwrapRef<RawBindings> & Data,
@@ -90,7 +125,16 @@ export type VueProxy<
90125
PropsOptions,
91126
ExtractPropTypes<PropsOptions>
92127
> &
93-
VueConstructorProxy<PropsOptions, RawBindings, Data, Computed, Methods>
128+
VueConstructorProxy<
129+
PropsOptions,
130+
RawBindings,
131+
Data,
132+
Computed,
133+
Methods,
134+
Mixin,
135+
Extends,
136+
Emits
137+
>
94138

95139
// public properties exposed on the proxy, which is used as the render context
96140
// in templates (as `this` in the render option)

src/component/defineAsyncComponent.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@ import {
88
ComponentOptionsWithProps,
99
} from './componentOptions'
1010

11-
type ComponentOptions =
11+
type Component = VueProxy<any, any, any, any, any>
12+
13+
type ComponentOrComponentOptions =
14+
// Component
15+
| Component
16+
// ComponentOptions
1217
| ComponentOptionsWithoutProps
1318
| ComponentOptionsWithArrayProps
1419
| ComponentOptionsWithProps
1520

16-
type Component = VueProxy<any, any, any, any, any>
17-
18-
type ComponentOrComponentOptions = ComponentOptions | Component
19-
2021
export type AsyncComponentResolveResult<T = ComponentOrComponentOptions> =
2122
| T
2223
| { default: T } // es modules

src/component/defineComponent.ts

Lines changed: 79 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,45 +9,109 @@ import {
99
import { VueProxy } from './componentProxy'
1010
import { Data } from './common'
1111
import { HasDefined } from '../types/basic'
12+
import { EmitsOptions } from '../runtimeContext'
1213

13-
// overload 1: object format with no props
14+
/**
15+
* overload 1: object format with no props
16+
*/
1417
export function defineComponent<
1518
RawBindings,
1619
D = Data,
1720
C extends ComputedOptions = {},
18-
M extends MethodOptions = {}
21+
M extends MethodOptions = {},
22+
Mixin = {},
23+
Extends = {},
24+
Emits extends EmitsOptions = {}
1925
>(
20-
options: ComponentOptionsWithoutProps<{}, RawBindings, D, C, M>
21-
): VueProxy<{}, RawBindings, D, C, M>
22-
23-
// overload 2: object format with array props declaration
24-
// props inferred as { [key in PropNames]?: any }
25-
// return type is for Vetur and TSX support
26+
options: ComponentOptionsWithoutProps<
27+
{},
28+
RawBindings,
29+
D,
30+
C,
31+
M,
32+
Mixin,
33+
Extends,
34+
Emits
35+
>
36+
): VueProxy<{}, RawBindings, D, C, M, Mixin, Extends, Emits>
37+
/**
38+
* overload 2: object format with array props declaration
39+
* props inferred as `{ [key in PropNames]?: any }`
40+
*
41+
* return type is for Vetur and TSX support
42+
*/
2643
export function defineComponent<
2744
PropNames extends string,
2845
RawBindings = Data,
2946
D = Data,
3047
C extends ComputedOptions = {},
3148
M extends MethodOptions = {},
49+
Mixin = {},
50+
Extends = {},
51+
Emits extends EmitsOptions = {},
3252
PropsOptions extends ComponentPropsOptions = ComponentPropsOptions
3353
>(
34-
options: ComponentOptionsWithArrayProps<PropNames, RawBindings, D, C, M>
35-
): VueProxy<Readonly<{ [key in PropNames]?: any }>, RawBindings, D, C, M>
54+
options: ComponentOptionsWithArrayProps<
55+
PropNames,
56+
RawBindings,
57+
D,
58+
C,
59+
M,
60+
Mixin,
61+
Extends,
62+
Emits
63+
>
64+
): VueProxy<
65+
Readonly<{ [key in PropNames]?: any }>,
66+
RawBindings,
67+
D,
68+
C,
69+
M,
70+
Mixin,
71+
Extends,
72+
Emits
73+
>
3674

37-
// overload 3: object format with object props declaration
38-
// see `ExtractPropTypes` in ./componentProps.ts
75+
/**
76+
* overload 3: object format with object props declaration
77+
*
78+
* see `ExtractPropTypes` in './componentProps.ts'
79+
*/
3980
export function defineComponent<
4081
Props,
4182
RawBindings = Data,
4283
D = Data,
4384
C extends ComputedOptions = {},
4485
M extends MethodOptions = {},
86+
Mixin = {},
87+
Extends = {},
88+
Emits extends EmitsOptions = {},
4589
PropsOptions extends ComponentPropsOptions = ComponentPropsOptions
4690
>(
4791
options: HasDefined<Props> extends true
48-
? ComponentOptionsWithProps<PropsOptions, RawBindings, D, C, M, Props>
49-
: ComponentOptionsWithProps<PropsOptions, RawBindings, D, C, M>
50-
): VueProxy<PropsOptions, RawBindings, D, C, M>
92+
? ComponentOptionsWithProps<
93+
PropsOptions,
94+
RawBindings,
95+
D,
96+
C,
97+
M,
98+
Mixin,
99+
Extends,
100+
Emits,
101+
Props
102+
>
103+
: ComponentOptionsWithProps<
104+
PropsOptions,
105+
RawBindings,
106+
D,
107+
C,
108+
M,
109+
Mixin,
110+
Extends,
111+
Emits
112+
>
113+
): VueProxy<PropsOptions, RawBindings, D, C, M, Mixin, Extends, Emits>
114+
51115
// implementation, close to no-op
52116
export function defineComponent(options: any) {
53117
return options as any

0 commit comments

Comments
 (0)