Skip to content

Commit

Permalink
perf(runtime-core): improve efficiency of normalizePropsOptions (#11409)
Browse files Browse the repository at this point in the history
close #9739
  • Loading branch information
skirtles-code authored Jul 29, 2024
1 parent 87923f6 commit 5680142
Showing 1 changed file with 34 additions and 31 deletions.
65 changes: 34 additions & 31 deletions packages/runtime-core/src/componentProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,10 @@ export type ExtractDefaultPropTypes<O> = O extends object
{ [K in keyof Pick<O, DefaultKeys<O>>]: InferPropType<O[K]> }
: {}

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)
Expand Down Expand Up @@ -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 `<Comp checked="">` or `<Comp checked="checked">`
// 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)
}
}
}
Expand All @@ -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<any>): string {
Expand All @@ -617,22 +636,6 @@ function getType(ctor: Prop<any>): string {
return ''
}

function isSameType(a: Prop<any>, b: Prop<any>): boolean {
return getType(a) === getType(b)
}

function getTypeIndex(
type: Prop<any>,
expectedTypes: PropType<any> | 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
*/
Expand Down

0 comments on commit 5680142

Please sign in to comment.