@@ -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,32 @@ 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 shouldCastTrue = true
567+
568+ const checkForBoolean = (
569+ type : PropConstructor | true | null | undefined ,
570+ ) => {
571+ const typeName = isFunction ( type ) && type . name
572+
573+ // If we find `String` before `Boolean`, e.g. `[String, Boolean]`, we need to handle the casting slightly
574+ // differently. Props passed as `<Comp checked="">` or `<Comp checked="checked">` will either be treated as
575+ // strings or converted to a boolean `true`, depending on the order of the types.
576+ if ( typeName === 'String' ) {
577+ shouldCastTrue = false
576578 }
579+
580+ return typeName === 'Boolean'
581+ }
582+
583+ const shouldCast = isArray ( propType )
584+ ? propType . some ( checkForBoolean )
585+ : checkForBoolean ( propType )
586+ prop [ BooleanFlags . shouldCast ] = shouldCast
587+ prop [ BooleanFlags . shouldCastTrue ] = shouldCastTrue
588+ // if the prop needs boolean casting or default value
589+ if ( shouldCast || hasOwn ( prop , 'default' ) ) {
590+ needCastKeys . push ( normalizedKey )
577591 }
578592 }
579593 }
@@ -595,6 +609,7 @@ function validatePropName(key: string) {
595609 return false
596610}
597611
612+ // dev only
598613// use function string name to check type constructors
599614// so that it works across vms / iframes.
600615function getType ( ctor : Prop < any > ) : string {
@@ -617,22 +632,6 @@ function getType(ctor: Prop<any>): string {
617632 return ''
618633}
619634
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-
636635/**
637636 * dev only
638637 */
0 commit comments