]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(runtime-core): add skipCheck for prop (#7548)
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Tue, 28 Mar 2023 14:29:54 +0000 (22:29 +0800)
committerGitHub <noreply@github.com>
Tue, 28 Mar 2023 14:29:54 +0000 (22:29 +0800)
packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap
packages/compiler-sfc/__tests__/compileScript.spec.ts
packages/compiler-sfc/src/compileScript.ts
packages/runtime-core/__tests__/componentProps.spec.ts
packages/runtime-core/src/componentProps.ts

index 9655e7385c4b11feabd0b9f05e618d8708876aec..6dcac98204e5c98955ab60ebda09c5a1cddefbc1 100644 (file)
@@ -1715,7 +1715,9 @@ export default /*#__PURE__*/_defineComponent({
     foo: { type: [Function, null], required: true },
     unknown: { type: null, required: true },
     unknownUnion: { type: null, required: true },
-    unknownIntersection: { type: Object, required: true }
+    unknownIntersection: { type: Object, required: true },
+    unknownUnionWithBoolean: { type: Boolean, required: true, skipCheck: true },
+    unknownUnionWithFunction: { type: Function, required: true, skipCheck: true }
   },
   setup(__props: any, { expose: __expose }) {
   __expose();
index 8aa5951104a89b9bb545a4749a2a06bd122f678b..8e3ef4e63eaf46338188e1bf3eeb562abb407ab9 100644 (file)
@@ -1042,6 +1042,8 @@ const emit = defineEmits(['a', 'b'])
         unknown: UnknownType
         unknownUnion: UnknownType | string
         unknownIntersection: UnknownType & Object
+        unknownUnionWithBoolean: UnknownType | boolean
+        unknownUnionWithFunction: UnknownType | (() => any)
       }>()
       </script>`)
       assertCode(content)
@@ -1093,7 +1095,13 @@ const emit = defineEmits(['a', 'b'])
       expect(content).toMatch(`unknownUnion: { type: null, required: true }`)
       // intersection containing unknown type: narrow to the known types
       expect(content).toMatch(
-        `unknownIntersection: { type: Object, required: true }`
+        `unknownIntersection: { type: Object, required: true },`
+      )
+      expect(content).toMatch(
+        `unknownUnionWithBoolean: { type: Boolean, required: true, skipCheck: true },`
+      )
+      expect(content).toMatch(
+        `unknownUnionWithFunction: { type: Function, required: true, skipCheck: true }`
       )
       expect(bindings).toStrictEqual({
         string: BindingTypes.PROPS,
@@ -1131,7 +1139,9 @@ const emit = defineEmits(['a', 'b'])
         nonNull: BindingTypes.PROPS,
         unknown: BindingTypes.PROPS,
         unknownUnion: BindingTypes.PROPS,
-        unknownIntersection: BindingTypes.PROPS
+        unknownIntersection: BindingTypes.PROPS,
+        unknownUnionWithBoolean: BindingTypes.PROPS,
+        unknownUnionWithFunction: BindingTypes.PROPS
       })
     })
 
index 6a4ac52b1eaa6a8b73a63a2c9134be1fb142643f..3ec54e8010a75285f0b57c71ea361946c74714df 100644 (file)
@@ -888,11 +888,11 @@ export function compileScript(
           }
         }
 
-        const { type, required } = props[key]
+        const { type, required, skipCheck } = props[key]
         if (!isProd) {
           return `${key}: { type: ${toRuntimeTypeString(
             type
-          )}, required: ${required}${
+          )}, required: ${required}${skipCheck ? ', skipCheck: true' : ''}${
             defaultString ? `, ${defaultString}` : ``
           } }`
         } else if (
@@ -1964,6 +1964,7 @@ interface PropTypeData {
   key: string
   type: string[]
   required: boolean
+  skipCheck: boolean
 }
 
 function recordType(node: Node, declaredTypes: Record<string, string[]>) {
@@ -1993,19 +1994,26 @@ function extractRuntimeProps(
       m.key.type === 'Identifier'
     ) {
       let type: string[] | undefined
+      let skipCheck = false
       if (m.type === 'TSMethodSignature') {
         type = ['Function']
       } else if (m.typeAnnotation) {
         type = inferRuntimeType(m.typeAnnotation.typeAnnotation, declaredTypes)
         // skip check for result containing unknown types
         if (type.includes(UNKNOWN_TYPE)) {
-          type = [`null`]
+          if (type.includes('Boolean') || type.includes('Function')) {
+            type = type.filter(t => t !== UNKNOWN_TYPE)
+            skipCheck = true
+          } else {
+            type = ['null']
+          }
         }
       }
       props[m.key.name] = {
         key: m.key.name,
         required: !m.optional,
-        type: type || [`null`]
+        type: type || [`null`],
+        skipCheck
       }
     }
   }
index df46da6807a708f4dedbc40be7c6acd456b7e162..071a24f138dc073d70283edf2c7d2dab88426ab2 100644 (file)
@@ -335,7 +335,8 @@ describe('component props', () => {
         arr: { type: Array },
         obj: { type: Object },
         cls: { type: MyClass },
-        fn: { type: Function }
+        fn: { type: Function },
+        skipCheck: { type: [Boolean, Function], skipCheck: true }
       },
       setup() {
         return () => null
@@ -349,7 +350,8 @@ describe('component props', () => {
         arr: {},
         obj: 'false',
         cls: {},
-        fn: true
+        fn: true,
+        skipCheck: 'foo'
       }),
       nodeOps.createElement('div')
     )
@@ -374,6 +376,9 @@ describe('component props', () => {
     expect(
       `Invalid prop: type check failed for prop "cls". Expected MyClass, got Object`
     ).toHaveBeenWarned()
+    expect(
+      `Invalid prop: type check failed for prop "skipCheck". Expected Boolean | Function, got String with value "foo".`
+    ).not.toHaveBeenWarned()
   })
 
   // #3495
index db8bf73a9a1f1d5ce0a9f476f17153d8f8dec0c9..03c83990c577f870350744bf09068120c40e9861 100644 (file)
@@ -58,6 +58,7 @@ export interface PropOptions<T = any, D = T> {
   required?: boolean
   default?: D | DefaultFactory<D> | null | undefined | object
   validator?(value: unknown): boolean
+  skipCheck?: boolean
 }
 
 export type PropType<T> = PropConstructor<T> | PropConstructor<T>[]
@@ -608,7 +609,7 @@ function validateProp(
   prop: PropOptions,
   isAbsent: boolean
 ) {
-  const { type, required, validator } = prop
+  const { type, required, validator, skipCheck } = prop
   // required!
   if (required && isAbsent) {
     warn('Missing required prop: "' + name + '"')
@@ -619,7 +620,7 @@ function validateProp(
     return
   }
   // type check
-  if (type != null && type !== true) {
+  if (type != null && type !== true && !skipCheck) {
     let isValid = false
     const types = isArray(type) ? type : [type]
     const expectedTypes = []