diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 9d7b7f0e4a5..ce39f150ef5 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,36 @@ 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 shouldCast = false + let shouldCastTrue = true + + if (isArray(propType)) { + for (let index = 0; index < propType.length; ++index) { + const type = propType[index] + const typeName = isFunction(type) && type.name + + if (typeName === 'Boolean') { + shouldCast = true + break + } else if (typeName === 'String') { + // 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. + shouldCastTrue = false + } } + } else { + shouldCast = isFunction(propType) && propType.name === 'Boolean' + } + + 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 +613,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 +636,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 */