]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
perf(runtime-core): improve efficiency of normalizePropsOptions (#11409)
authorskirtle <65301168+skirtles-code@users.noreply.github.com>
Mon, 29 Jul 2024 13:47:23 +0000 (14:47 +0100)
committerGitHub <noreply@github.com>
Mon, 29 Jul 2024 13:47:23 +0000 (21:47 +0800)
close #9739

packages/runtime-core/src/componentProps.ts

index 9d7b7f0e4a52ce49a4544241ee66d07e14459c21..ce39f150ef54079ccb5739c010dac0955e17e8a0 100644 (file)
@@ -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)
@@ -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)
         }
       }
     }
@@ -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 {
@@ -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
  */