diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 9d7b7f0e4a5..216dc6e2da8 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -174,12 +174,10 @@ export type ExtractDefaultPropTypes = O extends object { [K in keyof Pick>]: InferPropType } : {} -type NormalizedProp = - | null - | (PropOptions & { - [BooleanFlags.shouldCast]?: boolean - [BooleanFlags.shouldCastTrue]?: boolean - }) +type NormalizedProp = PropOptions & { + [BooleanFlags.shouldCast]?: boolean + [BooleanFlags.shouldCastTrue]?: boolean +} // normalized value is a tuple of the actual normalized options // and an array of prop keys that need value casting (booleans and defaults) @@ -564,16 +562,32 @@ export function normalizePropsOptions( const opt = raw[key] const prop: NormalizedProp = (normalized[normalizedKey] = isArray(opt) || isFunction(opt) ? { type: opt } : extend({}, opt)) - if (prop) { - const booleanIndex = getTypeIndex(Boolean, prop.type) - const stringIndex = getTypeIndex(String, prop.type) - prop[BooleanFlags.shouldCast] = booleanIndex > -1 - prop[BooleanFlags.shouldCastTrue] = - stringIndex < 0 || booleanIndex < stringIndex - // if the prop needs boolean casting or default value - if (booleanIndex > -1 || hasOwn(prop, 'default')) { - needCastKeys.push(normalizedKey) + const propType = prop.type + let shouldCastTrue = true + + const checkForBoolean = ( + type: PropConstructor | true | null | undefined, + ) => { + const typeName = isFunction(type) && type.name + + // If we find `String` before `Boolean`, e.g. `[String, Boolean]`, we need to handle the casting slightly + // differently. Props passed as `` or `` will either be treated as + // strings or converted to a boolean `true`, depending on the order of the types. + if (typeName === 'String') { + shouldCastTrue = false } + + return typeName === 'Boolean' + } + + const shouldCast = isArray(propType) + ? propType.some(checkForBoolean) + : checkForBoolean(propType) + prop[BooleanFlags.shouldCast] = shouldCast + prop[BooleanFlags.shouldCastTrue] = shouldCastTrue + // if the prop needs boolean casting or default value + if (shouldCast || hasOwn(prop, 'default')) { + needCastKeys.push(normalizedKey) } } } @@ -595,6 +609,7 @@ function validatePropName(key: string) { return false } +// dev only // use function string name to check type constructors // so that it works across vms / iframes. function getType(ctor: Prop): string { @@ -617,22 +632,6 @@ function getType(ctor: Prop): string { return '' } -function isSameType(a: Prop, b: Prop): boolean { - return getType(a) === getType(b) -} - -function getTypeIndex( - type: Prop, - expectedTypes: PropType | void | null | true, -): number { - if (isArray(expectedTypes)) { - return expectedTypes.findIndex(t => isSameType(t, type)) - } else if (isFunction(expectedTypes)) { - return isSameType(expectedTypes, type) ? 0 : -1 - } - return -1 -} - /** * dev only */