Skip to content

Commit 498fb0b

Browse files
committed
types(defineComponent): props support in TypeScript
1 parent 72d2b26 commit 498fb0b

File tree

3 files changed

+98
-89
lines changed

3 files changed

+98
-89
lines changed

packages/runtime-core/src/apiDefineComponent.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ export type DefineComponent<
7070
E,
7171
EE,
7272
Defaults
73-
> &
74-
PP
73+
> & {
74+
props: PropsOrPropOptions
75+
} & PP
7576

7677
// defineComponent is a utility that is primarily used for type inference
7778
// when declaring components. Type inference is provided in the component
@@ -112,7 +113,7 @@ export function defineComponent<
112113
E,
113114
EE
114115
>
115-
): DefineComponent<Props, RawBindings, D, C, M, Mixin, Extends, E, EE>
116+
): DefineComponent<undefined, RawBindings, D, C, M, Mixin, Extends, E, EE>
116117

117118
// overload 3: object format with array props declaration
118119
// props inferred as { [key in PropNames]?: any }

packages/runtime-core/src/componentProps.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ export type ExtractPropTypes<O> = O extends object
119119
? { [K in keyof O]?: unknown } & // This is needed to keep the relation between the option prop and the props, allowing to use ctrl+click to navigate to the prop options. see: #3656
120120
{ [K in RequiredKeys<O>]: InferPropType<O[K]> } &
121121
{ [K in OptionalKeys<O>]?: InferPropType<O[K]> }
122+
: O extends undefined
123+
? {}
122124
: { [K in string]: any }
123125

124126
const enum BooleanFlags {

test-dts/defineComponent.test-d.tsx

Lines changed: 92 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -46,93 +46,97 @@ describe('with object props', () => {
4646

4747
type GT = string & { __brand: unknown }
4848

49-
const MyComponent = defineComponent({
50-
props: {
51-
a: Number,
52-
// required should make property non-void
53-
b: {
54-
type: String,
55-
required: true
56-
},
57-
e: Function,
58-
h: Boolean,
59-
j: Function as PropType<undefined | (() => string | undefined)>,
60-
// default value should infer type and make it non-void
61-
bb: {
62-
default: 'hello'
63-
},
64-
bbb: {
65-
// Note: default function value requires arrow syntax + explicit
66-
// annotation
67-
default: (props: any) => (props.bb as string) || 'foo'
68-
},
69-
bbbb: {
70-
type: String,
71-
default: undefined
72-
},
73-
bbbbb: {
74-
type: String,
75-
default: () => undefined
76-
},
77-
// explicit type casting
78-
cc: Array as PropType<string[]>,
79-
// required + type casting
80-
dd: {
81-
type: Object as PropType<{ n: 1 }>,
82-
required: true
83-
},
84-
// return type
85-
ee: Function as PropType<() => string>,
86-
// arguments + object return
87-
ff: Function as PropType<(a: number, b: string) => { a: boolean }>,
88-
// explicit type casting with constructor
89-
ccc: Array as () => string[],
90-
// required + contructor type casting
91-
ddd: {
92-
type: Array as () => string[],
93-
required: true
94-
},
95-
// required + object return
96-
eee: {
97-
type: Function as PropType<() => { a: string }>,
98-
required: true
99-
},
100-
// required + arguments + object return
101-
fff: {
102-
type: Function as PropType<(a: number, b: string) => { a: boolean }>,
103-
required: true
104-
},
105-
hhh: {
106-
type: Boolean,
107-
required: true
108-
},
109-
// default + type casting
110-
ggg: {
111-
type: String as PropType<'foo' | 'bar'>,
112-
default: 'foo'
113-
},
114-
// default + function
115-
ffff: {
116-
type: Function as PropType<(a: number, b: string) => { a: boolean }>,
117-
default: (a: number, b: string) => ({ a: a > +b })
118-
},
119-
// union + function with different return types
120-
iii: Function as PropType<(() => string) | (() => number)>,
121-
// union + function with different args & same return type
122-
jjj: {
123-
type: Function as PropType<
124-
((arg1: string) => string) | ((arg1: string, arg2: string) => string)
125-
>,
126-
required: true
127-
},
128-
kkk: null,
129-
validated: {
130-
type: String,
131-
// validator requires explicit annotation
132-
validator: (val: unknown) => val !== ''
133-
},
134-
date: Date
49+
const props = {
50+
a: Number,
51+
// required should make property non-void
52+
b: {
53+
type: String,
54+
required: true as true
55+
},
56+
e: Function,
57+
h: Boolean,
58+
j: Function as PropType<undefined | (() => string | undefined)>,
59+
// default value should infer type and make it non-void
60+
bb: {
61+
default: 'hello'
62+
},
63+
bbb: {
64+
// Note: default function value requires arrow syntax + explicit
65+
// annotation
66+
default: (props: any) => (props.bb as string) || 'foo'
67+
},
68+
bbbb: {
69+
type: String,
70+
default: undefined
71+
},
72+
bbbbb: {
73+
type: String,
74+
default: () => undefined
75+
},
76+
// explicit type casting
77+
cc: Array as PropType<string[]>,
78+
// required + type casting
79+
dd: {
80+
type: Object as PropType<{ n: 1 }>,
81+
required: true as true
82+
},
83+
// return type
84+
ee: Function as PropType<() => string>,
85+
// arguments + object return
86+
ff: Function as PropType<(a: number, b: string) => { a: boolean }>,
87+
// explicit type casting with constructor
88+
ccc: Array as () => string[],
89+
// required + contructor type casting
90+
ddd: {
91+
type: Array as () => string[],
92+
required: true as true
13593
},
94+
// required + object return
95+
eee: {
96+
type: Function as PropType<() => { a: string }>,
97+
required: true as true
98+
},
99+
// required + arguments + object return
100+
fff: {
101+
type: Function as PropType<(a: number, b: string) => { a: boolean }>,
102+
required: true as true
103+
},
104+
hhh: {
105+
type: Boolean,
106+
required: true as true
107+
},
108+
// default + type casting
109+
ggg: {
110+
type: String as PropType<'foo' | 'bar'>,
111+
default: 'foo'
112+
},
113+
// default + function
114+
ffff: {
115+
type: Function as PropType<(a: number, b: string) => { a: boolean }>,
116+
default: (a: number, b: string) => ({ a: a > +b })
117+
},
118+
// union + function with different return types
119+
iii: Function as PropType<(() => string) | (() => number)>,
120+
// union + function with different args & same return type
121+
jjj: {
122+
type: Function as PropType<
123+
((arg1: string) => string) | ((arg1: string, arg2: string) => string)
124+
>,
125+
required: true as true
126+
},
127+
kkk: null,
128+
validated: {
129+
type: String,
130+
// validator requires explicit annotation
131+
validator: (val: unknown) => val !== ''
132+
},
133+
date: Date
134+
}
135+
136+
type ExpectedPropsType = typeof props
137+
138+
const MyComponent = defineComponent({
139+
props,
136140
setup(props) {
137141
// type assertion. See https://github.com/SamVerschueren/tsd
138142
expectType<ExpectedProps['a']>(props.a)
@@ -249,6 +253,8 @@ describe('with object props', () => {
249253

250254
expectType<Component>(MyComponent)
251255

256+
expectType<ExpectedPropsType>(MyComponent.props)
257+
252258
// Test TSX
253259
expectType<JSX.Element>(
254260
<MyComponent

0 commit comments

Comments
 (0)