Skip to content

Commit a072d50

Browse files
wonderful-pandayyx990803
authored andcommitted
fix(runtime-core): optional props from Mixin/Extends are treated as required (#2039)
1 parent 7e68ddd commit a072d50

File tree

5 files changed

+123
-28
lines changed

5 files changed

+123
-28
lines changed

packages/runtime-core/src/apiDefineComponent.ts

+15-8
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ import {
1313
AllowedComponentProps,
1414
ComponentCustomProps
1515
} from './component'
16-
import { ExtractPropTypes, ComponentPropsOptions } from './componentProps'
16+
import {
17+
ExtractPropTypes,
18+
ComponentPropsOptions,
19+
ExtractDefaultPropTypes
20+
} from './componentProps'
1721
import { EmitsOptions } from './componentEmits'
1822
import { isFunction } from '@vue/shared'
1923
import { VNodeProps } from './vnode'
@@ -37,32 +41,35 @@ export type DefineComponent<
3741
E extends EmitsOptions = Record<string, any>,
3842
EE extends string = string,
3943
PP = PublicProps,
40-
RequiredProps = Readonly<ExtractPropTypes<PropsOrPropOptions>>,
41-
OptionalProps = Readonly<ExtractPropTypes<PropsOrPropOptions, false>>
44+
Props = Readonly<ExtractPropTypes<PropsOrPropOptions>>,
45+
Defaults = ExtractDefaultPropTypes<PropsOrPropOptions>
4246
> = ComponentPublicInstanceConstructor<
4347
CreateComponentPublicInstance<
44-
OptionalProps,
48+
Props,
4549
RawBindings,
4650
D,
4751
C,
4852
M,
4953
Mixin,
5054
Extends,
5155
E,
52-
PP & OptionalProps
56+
PP & Props,
57+
Defaults,
58+
true
5359
> &
54-
RequiredProps
60+
Props
5561
> &
5662
ComponentOptionsBase<
57-
RequiredProps,
63+
Props,
5864
RawBindings,
5965
D,
6066
C,
6167
M,
6268
Mixin,
6369
Extends,
6470
E,
65-
EE
71+
EE,
72+
Defaults
6673
> &
6774
PP
6875

packages/runtime-core/src/componentOptions.ts

+61-11
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ import {
4242
WritableComputedOptions,
4343
toRaw
4444
} from '@vue/reactivity'
45-
import { ComponentObjectPropsOptions, ExtractPropTypes } from './componentProps'
45+
import {
46+
ComponentObjectPropsOptions,
47+
ExtractPropTypes,
48+
ExtractDefaultPropTypes
49+
} from './componentProps'
4650
import { EmitsOptions } from './componentEmits'
4751
import { Directive } from './directives'
4852
import {
@@ -81,7 +85,8 @@ export interface ComponentOptionsBase<
8185
Mixin extends ComponentOptionsMixin,
8286
Extends extends ComponentOptionsMixin,
8387
E extends EmitsOptions,
84-
EE extends string = string
88+
EE extends string = string,
89+
Defaults = {}
8590
>
8691
extends LegacyOptions<Props, D, C, M, Mixin, Extends>,
8792
ComponentInternalOptions,
@@ -148,6 +153,8 @@ export interface ComponentOptionsBase<
148153
__isFragment?: never
149154
__isTeleport?: never
150155
__isSuspense?: never
156+
157+
__defaults?: Defaults
151158
}
152159

153160
export type ComponentOptionsWithoutProps<
@@ -159,8 +166,20 @@ export type ComponentOptionsWithoutProps<
159166
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
160167
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
161168
E extends EmitsOptions = EmitsOptions,
162-
EE extends string = string
163-
> = ComponentOptionsBase<Props, RawBindings, D, C, M, Mixin, Extends, E, EE> & {
169+
EE extends string = string,
170+
Defaults = {}
171+
> = ComponentOptionsBase<
172+
Props,
173+
RawBindings,
174+
D,
175+
C,
176+
M,
177+
Mixin,
178+
Extends,
179+
E,
180+
EE,
181+
Defaults
182+
> & {
164183
props?: undefined
165184
} & ThisType<
166185
CreateComponentPublicInstance<
@@ -172,7 +191,9 @@ export type ComponentOptionsWithoutProps<
172191
Mixin,
173192
Extends,
174193
E,
175-
Readonly<Props>
194+
Readonly<Props>,
195+
Defaults,
196+
false
176197
>
177198
>
178199

@@ -187,7 +208,18 @@ export type ComponentOptionsWithArrayProps<
187208
E extends EmitsOptions = EmitsOptions,
188209
EE extends string = string,
189210
Props = Readonly<{ [key in PropNames]?: any }>
190-
> = ComponentOptionsBase<Props, RawBindings, D, C, M, Mixin, Extends, E, EE> & {
211+
> = ComponentOptionsBase<
212+
Props,
213+
RawBindings,
214+
D,
215+
C,
216+
M,
217+
Mixin,
218+
Extends,
219+
E,
220+
EE,
221+
{}
222+
> & {
191223
props: PropNames[]
192224
} & ThisType<
193225
CreateComponentPublicInstance<
@@ -212,8 +244,20 @@ export type ComponentOptionsWithObjectProps<
212244
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
213245
E extends EmitsOptions = EmitsOptions,
214246
EE extends string = string,
215-
Props = Readonly<ExtractPropTypes<PropsOptions>>
216-
> = ComponentOptionsBase<Props, RawBindings, D, C, M, Mixin, Extends, E, EE> & {
247+
Props = Readonly<ExtractPropTypes<PropsOptions>>,
248+
Defaults = ExtractDefaultPropTypes<PropsOptions>
249+
> = ComponentOptionsBase<
250+
Props,
251+
RawBindings,
252+
D,
253+
C,
254+
M,
255+
Mixin,
256+
Extends,
257+
E,
258+
EE,
259+
Defaults
260+
> & {
217261
props: PropsOptions & ThisType<void>
218262
} & ThisType<
219263
CreateComponentPublicInstance<
@@ -224,7 +268,10 @@ export type ComponentOptionsWithObjectProps<
224268
M,
225269
Mixin,
226270
Extends,
227-
E
271+
E,
272+
Props,
273+
Defaults,
274+
false
228275
>
229276
>
230277

@@ -261,6 +308,7 @@ export type ComponentOptionsMixin = ComponentOptionsBase<
261308
any,
262309
any,
263310
any,
311+
any,
264312
any
265313
>
266314

@@ -347,20 +395,22 @@ interface LegacyOptions<
347395
delimiters?: [string, string]
348396
}
349397

350-
export type OptionTypesKeys = 'P' | 'B' | 'D' | 'C' | 'M'
398+
export type OptionTypesKeys = 'P' | 'B' | 'D' | 'C' | 'M' | 'Defaults'
351399

352400
export type OptionTypesType<
353401
P = {},
354402
B = {},
355403
D = {},
356404
C extends ComputedOptions = {},
357-
M extends MethodOptions = {}
405+
M extends MethodOptions = {},
406+
Defaults = {}
358407
> = {
359408
P: P
360409
B: B
361410
D: D
362411
C: C
363412
M: M
413+
Defaults: Defaults
364414
}
365415

366416
const enum OptionTypes {

packages/runtime-core/src/componentProps.ts

+9
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ type OptionalKeys<T, MakeDefaultRequired> = Exclude<
7676
RequiredKeys<T, MakeDefaultRequired>
7777
>
7878

79+
type DefaultKeys<T> = {
80+
[K in keyof T]: T[K] extends { default: any } ? K : never
81+
}[keyof T]
82+
7983
type InferPropType<T> = T extends null
8084
? any // null & true would fail to infer
8185
: T extends { type: null | true }
@@ -99,6 +103,11 @@ const enum BooleanFlags {
99103
shouldCastTrue
100104
}
101105

106+
// extract props which defined with default from prop options
107+
export type ExtractDefaultPropTypes<O> = O extends object
108+
? { [K in DefaultKeys<O>]: InferPropType<O[K]> }
109+
: {}
110+
102111
type NormalizedProp =
103112
| null
104113
| (PropOptions & {

packages/runtime-core/src/componentPublicInstance.ts

+18-6
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,11 @@ type MixinToOptionTypes<T> = T extends ComponentOptionsBase<
7777
infer M,
7878
infer Mixin,
7979
infer Extends,
80-
any
80+
any,
81+
any,
82+
infer Defaults
8183
>
82-
? OptionTypesType<P & {}, B & {}, D & {}, C & {}, M & {}> &
84+
? OptionTypesType<P & {}, B & {}, D & {}, C & {}, M & {}, Defaults & {}> &
8385
IntersectionMixin<Mixin> &
8486
IntersectionMixin<Extends>
8587
: never
@@ -130,14 +132,18 @@ export type CreateComponentPublicInstance<
130132
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
131133
E extends EmitsOptions = {},
132134
PublicProps = P,
135+
Defaults = {},
136+
MakeDefaultsOptional extends boolean = false,
133137
PublicMixin = IntersectionMixin<Mixin> & IntersectionMixin<Extends>,
134138
PublicP = UnwrapMixinsType<PublicMixin, 'P'> & EnsureNonVoid<P>,
135139
PublicB = UnwrapMixinsType<PublicMixin, 'B'> & EnsureNonVoid<B>,
136140
PublicD = UnwrapMixinsType<PublicMixin, 'D'> & EnsureNonVoid<D>,
137141
PublicC extends ComputedOptions = UnwrapMixinsType<PublicMixin, 'C'> &
138142
EnsureNonVoid<C>,
139143
PublicM extends MethodOptions = UnwrapMixinsType<PublicMixin, 'M'> &
140-
EnsureNonVoid<M>
144+
EnsureNonVoid<M>,
145+
PublicDefaults = UnwrapMixinsType<PublicMixin, 'Defaults'> &
146+
EnsureNonVoid<Defaults>
141147
> = ComponentPublicInstance<
142148
PublicP,
143149
PublicB,
@@ -146,7 +152,9 @@ export type CreateComponentPublicInstance<
146152
PublicM,
147153
E,
148154
PublicProps,
149-
ComponentOptionsBase<P, B, D, C, M, Mixin, Extends, E>
155+
PublicDefaults,
156+
MakeDefaultsOptional,
157+
ComponentOptionsBase<P, B, D, C, M, Mixin, Extends, E, string, Defaults>
150158
>
151159

152160
// public properties exposed on the proxy, which is used as the render context
@@ -159,11 +167,15 @@ export type ComponentPublicInstance<
159167
M extends MethodOptions = {},
160168
E extends EmitsOptions = {},
161169
PublicProps = P,
162-
Options = ComponentOptionsBase<any, any, any, any, any, any, any, any>
170+
Defaults = {},
171+
MakeDefaultsOptional extends boolean = false,
172+
Options = ComponentOptionsBase<any, any, any, any, any, any, any, any, any>
163173
> = {
164174
$: ComponentInternalInstance
165175
$data: D
166-
$props: P & PublicProps
176+
$props: MakeDefaultsOptional extends true
177+
? Partial<Defaults> & Omit<P & PublicProps, keyof Defaults>
178+
: P & PublicProps
167179
$attrs: Data
168180
$refs: Data
169181
$slots: Slots

test-dts/defineComponent.test-d.tsx

+20-3
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,11 @@ describe('extends with mixins', () => {
597597
type: String,
598598
default: 'mP1'
599599
},
600-
mP2: Boolean
600+
mP2: Boolean,
601+
mP3: {
602+
type: Boolean,
603+
required: true
604+
}
601605
},
602606
data() {
603607
return {
@@ -611,6 +615,10 @@ describe('extends with mixins', () => {
611615
p2: {
612616
type: Number,
613617
default: 2
618+
},
619+
p3: {
620+
type: Boolean,
621+
required: true
614622
}
615623
},
616624
data() {
@@ -663,11 +671,20 @@ describe('extends with mixins', () => {
663671
})
664672

665673
// Test TSX
666-
expectType<JSX.Element>(<MyComponent mP1="p1" mP2 p1 p2={1} z={'z'} />)
674+
expectType<JSX.Element>(<MyComponent mP1="p1" mP2 mP3 p1 p2={1} p3 z={'z'} />)
675+
676+
// mP1, mP2, p1, and p2 have default value. these are not required
677+
expectType<JSX.Element>(<MyComponent mP3 p3 z={'z'} />)
667678

668679
// missing required props
669680
// @ts-expect-error
670-
expectError(<MyComponent />)
681+
expectError(<MyComponent mP3 p3 /* z='z' */ />)
682+
// missing required props from mixin
683+
// @ts-expect-error
684+
expectError(<MyComponent /* mP3 */ p3 z="z" />)
685+
// missing required props from extends
686+
// @ts-expect-error
687+
expectError(<MyComponent mP3 /* p3 */ z="z" />)
671688

672689
// wrong prop types
673690
// @ts-expect-error

0 commit comments

Comments
 (0)