@@ -174,12 +174,10 @@ export type ExtractDefaultPropTypes<O> = O extends object
174174 { [ K in keyof Pick < O , DefaultKeys < O > > ] : InferPropType < O [ K ] > }
175175 : { }
176176
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+ }
183181
184182// normalized value is a tuple of the actual normalized options
185183// and an array of prop keys that need value casting (booleans and defaults)
@@ -564,16 +562,36 @@ export function normalizePropsOptions(
564562 const opt = raw [ key ]
565563 const prop : NormalizedProp = ( normalized [ normalizedKey ] =
566564 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+ }
576585 }
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 )
577595 }
578596 }
579597 }
@@ -595,6 +613,7 @@ function validatePropName(key: string) {
595613 return false
596614}
597615
616+ // dev only
598617// use function string name to check type constructors
599618// so that it works across vms / iframes.
600619function getType ( ctor : Prop < any > ) : string {
@@ -617,22 +636,6 @@ function getType(ctor: Prop<any>): string {
617636 return ''
618637}
619638
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-
636639/**
637640 * dev only
638641 */
0 commit comments