Skip to content

Commit 4cc9ca8

Browse files
authored
types(defineComponent): support for GlobalComponents, typed Directives and respect expose on defineComponent (#3399)
close #3367
1 parent 0e6e3c7 commit 4cc9ca8

15 files changed

+533
-86
lines changed

packages/dts-test/componentTypeExtensions.test-d.tsx

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
1-
import { defineComponent } from 'vue'
1+
import { type DefineComponent, type Directive, defineComponent } from 'vue'
22
import { expectType } from './utils'
33

44
declare module 'vue' {
55
interface ComponentCustomOptions {
66
test?(n: number): void
77
}
88

9+
interface GlobalDirectives {
10+
test: Directive
11+
}
12+
13+
interface GlobalComponents {
14+
RouterView: DefineComponent<{}>
15+
}
16+
917
interface ComponentCustomProperties {
1018
state?: 'stopped' | 'running'
1119
}
@@ -46,6 +54,8 @@ export const Custom = defineComponent({
4654
},
4755
})
4856

57+
expectType<Directive>(Custom.directives!.test)
58+
expectType<DefineComponent<{}>>(Custom.components!.RouterView)
4959
expectType<JSX.Element>(<Custom baz={1} />)
5060
expectType<JSX.Element>(<Custom custom={1} baz={1} />)
5161
expectType<JSX.Element>(<Custom bar="bar" baz={1} />)

packages/dts-test/defineComponent.test-d.tsx

+90
Original file line numberDiff line numberDiff line change
@@ -1501,18 +1501,108 @@ describe('should work when props type is incompatible with setup returned type '
15011501

15021502
describe('withKeys and withModifiers as pro', () => {
15031503
const onKeydown = withKeys(e => {}, [''])
1504+
// @ts-expect-error invalid modifiers
15041505
const onClick = withModifiers(e => {}, [''])
15051506
;<input onKeydown={onKeydown} onClick={onClick} />
15061507
})
15071508

1509+
// #3367 expose components types
1510+
describe('expose component types', () => {
1511+
const child = defineComponent({
1512+
props: {
1513+
a: String,
1514+
},
1515+
})
1516+
1517+
const parent = defineComponent({
1518+
components: {
1519+
child,
1520+
child2: {
1521+
template: `<div></div>`,
1522+
},
1523+
},
1524+
})
1525+
1526+
expectType<typeof child>(parent.components!.child)
1527+
expectType<Component>(parent.components!.child2)
1528+
1529+
// global components
1530+
expectType<Readonly<KeepAliveProps>>(
1531+
new parent.components!.KeepAlive().$props,
1532+
)
1533+
expectType<Readonly<KeepAliveProps>>(new child.components!.KeepAlive().$props)
1534+
1535+
// runtime-dom components
1536+
expectType<Readonly<TransitionProps>>(
1537+
new parent.components!.Transition().$props,
1538+
)
1539+
expectType<Readonly<TransitionProps>>(
1540+
new child.components!.Transition().$props,
1541+
)
1542+
})
1543+
1544+
describe('directive typing', () => {
1545+
const customDirective: Directive = {
1546+
created(_) {},
1547+
}
1548+
1549+
const comp = defineComponent({
1550+
props: {
1551+
a: String,
1552+
},
1553+
directives: {
1554+
customDirective,
1555+
localDirective: {
1556+
created(_, { arg }) {
1557+
expectType<string | undefined>(arg)
1558+
},
1559+
},
1560+
},
1561+
})
1562+
1563+
expectType<typeof customDirective>(comp.directives!.customDirective)
1564+
expectType<Directive>(comp.directives!.localDirective)
1565+
1566+
// global directive
1567+
expectType<typeof vShow>(comp.directives!.vShow)
1568+
})
1569+
1570+
describe('expose typing', () => {
1571+
const Comp = defineComponent({
1572+
expose: ['a', 'b'],
1573+
props: {
1574+
some: String,
1575+
},
1576+
data() {
1577+
return { a: 1, b: '2', c: 1 }
1578+
},
1579+
})
1580+
1581+
expectType<Array<'a' | 'b'>>(Comp.expose!)
1582+
1583+
const vm = new Comp()
1584+
// internal should still be exposed
1585+
vm.$props
1586+
1587+
expectType<number>(vm.a)
1588+
expectType<string>(vm.b)
1589+
1590+
// @ts-expect-error shouldn't be exposed
1591+
vm.c
1592+
})
1593+
15081594
import type {
15091595
AllowedComponentProps,
15101596
ComponentCustomProps,
15111597
ComponentOptionsMixin,
15121598
DefineComponent,
1599+
Directive,
15131600
EmitsOptions,
15141601
ExtractPropTypes,
1602+
KeepAliveProps,
1603+
TransitionProps,
15151604
VNodeProps,
1605+
vShow,
15161606
} from 'vue'
15171607

15181608
// code generated by tsc / vue-tsc, make sure this continues to work
+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { type Directive, type ObjectDirective, vModelText } from 'vue'
2+
import { describe, expectType } from './utils'
3+
4+
type ExtractBinding<T> = T extends (
5+
el: any,
6+
binding: infer B,
7+
vnode: any,
8+
prev: any,
9+
) => any
10+
? B
11+
: never
12+
13+
declare function testDirective<
14+
Value,
15+
Modifiers extends string = string,
16+
Arg extends string = string,
17+
>(): ExtractBinding<Directive<any, Value, Modifiers, Arg>>
18+
19+
describe('vmodel', () => {
20+
expectType<ObjectDirective<any, any, 'trim' | 'number' | 'lazy', string>>(
21+
vModelText,
22+
)
23+
// @ts-expect-error
24+
expectType<ObjectDirective<any, any, 'not-valid', string>>(vModelText)
25+
})
26+
27+
describe('custom', () => {
28+
expectType<{
29+
value: number
30+
oldValue: number | null
31+
arg?: 'Arg'
32+
modifiers: Record<'a' | 'b', boolean>
33+
}>(testDirective<number, 'a' | 'b', 'Arg'>())
34+
35+
expectType<{
36+
value: number
37+
oldValue: number | null
38+
arg?: 'Arg'
39+
modifiers: Record<'a' | 'b', boolean>
40+
// @ts-expect-error
41+
}>(testDirective<number, 'a', 'Arg'>())
42+
43+
expectType<{
44+
value: number
45+
oldValue: number | null
46+
arg?: 'Arg'
47+
modifiers: Record<'a' | 'b', boolean>
48+
// @ts-expect-error
49+
}>(testDirective<number, 'a' | 'b', 'Argx'>())
50+
51+
expectType<{
52+
value: number
53+
oldValue: number | null
54+
arg?: 'Arg'
55+
modifiers: Record<'a' | 'b', boolean>
56+
// @ts-expect-error
57+
}>(testDirective<string, 'a' | 'b', 'Arg'>())
58+
})

packages/runtime-core/src/apiDefineComponent.ts

+62-10
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@ import type {
66
ComponentOptionsWithArrayProps,
77
ComponentOptionsWithObjectProps,
88
ComponentOptionsWithoutProps,
9+
ComponentProvideOptions,
910
ComputedOptions,
1011
MethodOptions,
1112
RenderFunction,
1213
} from './componentOptions'
1314
import type {
1415
AllowedComponentProps,
16+
Component,
1517
ComponentCustomProps,
18+
GlobalComponents,
19+
GlobalDirectives,
1620
SetupContext,
1721
} from './component'
1822
import type {
@@ -29,6 +33,7 @@ import type {
2933
CreateComponentPublicInstance,
3034
} from './componentPublicInstance'
3135
import type { SlotsType } from './componentSlots'
36+
import type { Directive } from './directives'
3237

3338
export type PublicProps = VNodeProps &
3439
AllowedComponentProps &
@@ -55,6 +60,10 @@ export type DefineComponent<
5560
Props = ResolveProps<PropsOrPropOptions, E>,
5661
Defaults = ExtractDefaultPropTypes<PropsOrPropOptions>,
5762
S extends SlotsType = {},
63+
LC extends Record<string, Component> = {},
64+
Directives extends Record<string, Directive> = {},
65+
Exposed extends string = string,
66+
Provide extends ComponentProvideOptions = ComponentProvideOptions,
5867
> = ComponentPublicInstanceConstructor<
5968
CreateComponentPublicInstance<
6069
Props,
@@ -69,7 +78,10 @@ export type DefineComponent<
6978
Defaults,
7079
true,
7180
{},
72-
S
81+
S,
82+
LC & GlobalComponents,
83+
Directives & GlobalDirectives,
84+
Exposed
7385
>
7486
> &
7587
ComponentOptionsBase<
@@ -85,7 +97,11 @@ export type DefineComponent<
8597
Defaults,
8698
{},
8799
string,
88-
S
100+
S,
101+
LC & GlobalComponents,
102+
Directives & GlobalDirectives,
103+
Exposed,
104+
Provide
89105
> &
90106
PP
91107

@@ -166,9 +182,13 @@ export function defineComponent<
166182
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
167183
E extends EmitsOptions = {},
168184
EE extends string = string,
169-
S extends SlotsType = {},
170185
I extends ComponentInjectOptions = {},
171186
II extends string = string,
187+
S extends SlotsType = {},
188+
LC extends Record<string, Component> = {},
189+
Directives extends Record<string, Directive> = {},
190+
Exposed extends string = string,
191+
Provide extends ComponentProvideOptions = ComponentProvideOptions,
172192
>(
173193
options: ComponentOptionsWithoutProps<
174194
Props,
@@ -182,7 +202,11 @@ export function defineComponent<
182202
EE,
183203
I,
184204
II,
185-
S
205+
S,
206+
LC,
207+
Directives,
208+
Exposed,
209+
Provide
186210
>,
187211
): DefineComponent<
188212
Props,
@@ -197,7 +221,11 @@ export function defineComponent<
197221
PublicProps,
198222
ResolveProps<Props, E>,
199223
ExtractDefaultPropTypes<Props>,
200-
S
224+
S,
225+
LC,
226+
Directives,
227+
Exposed,
228+
Provide
201229
>
202230

203231
// overload 3: object format with array props declaration
@@ -216,6 +244,10 @@ export function defineComponent<
216244
S extends SlotsType = {},
217245
I extends ComponentInjectOptions = {},
218246
II extends string = string,
247+
LC extends Record<string, Component> = {},
248+
Directives extends Record<string, Directive> = {},
249+
Exposed extends string = string,
250+
Provide extends ComponentProvideOptions = ComponentProvideOptions,
219251
Props = Readonly<{ [key in PropNames]?: any }>,
220252
>(
221253
options: ComponentOptionsWithArrayProps<
@@ -230,7 +262,11 @@ export function defineComponent<
230262
EE,
231263
I,
232264
II,
233-
S
265+
S,
266+
LC,
267+
Directives,
268+
Exposed,
269+
Provide
234270
>,
235271
): DefineComponent<
236272
Props,
@@ -245,7 +281,11 @@ export function defineComponent<
245281
PublicProps,
246282
ResolveProps<Props, E>,
247283
ExtractDefaultPropTypes<Props>,
248-
S
284+
S,
285+
LC,
286+
Directives,
287+
Exposed,
288+
Provide
249289
>
250290

251291
// overload 4: object format with object props declaration
@@ -262,9 +302,13 @@ export function defineComponent<
262302
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
263303
E extends EmitsOptions = {},
264304
EE extends string = string,
265-
S extends SlotsType = {},
266305
I extends ComponentInjectOptions = {},
267306
II extends string = string,
307+
S extends SlotsType = {},
308+
LC extends Record<string, Component> = {},
309+
Directives extends Record<string, Directive> = {},
310+
Exposed extends string = string,
311+
Provide extends ComponentProvideOptions = ComponentProvideOptions,
268312
>(
269313
options: ComponentOptionsWithObjectProps<
270314
PropsOptions,
@@ -278,7 +322,11 @@ export function defineComponent<
278322
EE,
279323
I,
280324
II,
281-
S
325+
S,
326+
LC,
327+
Directives,
328+
Exposed,
329+
Provide
282330
>,
283331
): DefineComponent<
284332
PropsOptions,
@@ -293,7 +341,11 @@ export function defineComponent<
293341
PublicProps,
294342
ResolveProps<PropsOptions, E>,
295343
ExtractDefaultPropTypes<PropsOptions>,
296-
S
344+
S,
345+
LC,
346+
Directives,
347+
Exposed,
348+
Provide
297349
>
298350

299351
// implementation, close to no-op

0 commit comments

Comments
 (0)