@@ -174,12 +174,10 @@ export type ExtractDefaultPropTypes<O> = O extends object
174
174
{ [ K in keyof Pick < O , DefaultKeys < O > > ] : InferPropType < O [ K ] > }
175
175
: { }
176
176
177
- type NormalizedProp =
178
- | null
179
- | ( PropOptions & {
180
- [ BooleanFlags . shouldCast ] ?: boolean
181
- [ BooleanFlags . shouldCastTrue ] ?: boolean
182
- } )
177
+ type NormalizedProp = PropOptions & {
178
+ [ BooleanFlags . shouldCast ] ?: boolean
179
+ [ BooleanFlags . shouldCastTrue ] ?: boolean
180
+ }
183
181
184
182
// normalized value is a tuple of the actual normalized options
185
183
// and an array of prop keys that need value casting (booleans and defaults)
@@ -564,16 +562,36 @@ export function normalizePropsOptions(
564
562
const opt = raw [ key ]
565
563
const prop : NormalizedProp = ( normalized [ normalizedKey ] =
566
564
isArray ( opt ) || isFunction ( opt ) ? { type : opt } : extend ( { } , opt ) )
567
- if ( prop ) {
568
- const booleanIndex = getTypeIndex ( Boolean , prop . type )
569
- const stringIndex = getTypeIndex ( String , prop . type )
570
- prop [ BooleanFlags . shouldCast ] = booleanIndex > - 1
571
- prop [ BooleanFlags . shouldCastTrue ] =
572
- stringIndex < 0 || booleanIndex < stringIndex
573
- // if the prop needs boolean casting or default value
574
- if ( booleanIndex > - 1 || hasOwn ( prop , 'default' ) ) {
575
- needCastKeys . push ( normalizedKey )
565
+ const propType = prop . type
566
+ let shouldCast = false
567
+ let shouldCastTrue = true
568
+
569
+ if ( isArray ( propType ) ) {
570
+ for ( let index = 0 ; index < propType . length ; ++ index ) {
571
+ const type = propType [ index ]
572
+ const typeName = isFunction ( type ) && type . name
573
+
574
+ if ( typeName === 'Boolean' ) {
575
+ shouldCast = true
576
+ break
577
+ } else if ( typeName === 'String' ) {
578
+ // If we find `String` before `Boolean`, e.g. `[String, Boolean]`,
579
+ // we need to handle the casting slightly differently. Props
580
+ // passed as `<Comp checked="">` or `<Comp checked="checked">`
581
+ // will either be treated as strings or converted to a boolean
582
+ // `true`, depending on the order of the types.
583
+ shouldCastTrue = false
584
+ }
576
585
}
586
+ } else {
587
+ shouldCast = isFunction ( propType ) && propType . name === 'Boolean'
588
+ }
589
+
590
+ prop [ BooleanFlags . shouldCast ] = shouldCast
591
+ prop [ BooleanFlags . shouldCastTrue ] = shouldCastTrue
592
+ // if the prop needs boolean casting or default value
593
+ if ( shouldCast || hasOwn ( prop , 'default' ) ) {
594
+ needCastKeys . push ( normalizedKey )
577
595
}
578
596
}
579
597
}
@@ -595,6 +613,7 @@ function validatePropName(key: string) {
595
613
return false
596
614
}
597
615
616
+ // dev only
598
617
// use function string name to check type constructors
599
618
// so that it works across vms / iframes.
600
619
function getType ( ctor : Prop < any > ) : string {
@@ -617,22 +636,6 @@ function getType(ctor: Prop<any>): string {
617
636
return ''
618
637
}
619
638
620
- function isSameType ( a : Prop < any > , b : Prop < any > ) : boolean {
621
- return getType ( a ) === getType ( b )
622
- }
623
-
624
- function getTypeIndex (
625
- type : Prop < any > ,
626
- expectedTypes : PropType < any > | void | null | true ,
627
- ) : number {
628
- if ( isArray ( expectedTypes ) ) {
629
- return expectedTypes . findIndex ( t => isSameType ( t , type ) )
630
- } else if ( isFunction ( expectedTypes ) ) {
631
- return isSameType ( expectedTypes , type ) ? 0 : - 1
632
- }
633
- return - 1
634
- }
635
-
636
639
/**
637
640
* dev only
638
641
*/
0 commit comments