Skip to content

Commit 63ad77f

Browse files
authored
feat(runtime-core): add skipCheck for prop (#7548)
1 parent 1bde9fb commit 63ad77f

File tree

5 files changed

+37
-11
lines changed

5 files changed

+37
-11
lines changed

packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap

+3-1
Original file line numberDiff line numberDiff line change
@@ -1715,7 +1715,9 @@ export default /*#__PURE__*/_defineComponent({
17151715
foo: { type: [Function, null], required: true },
17161716
unknown: { type: null, required: true },
17171717
unknownUnion: { type: null, required: true },
1718-
unknownIntersection: { type: Object, required: true }
1718+
unknownIntersection: { type: Object, required: true },
1719+
unknownUnionWithBoolean: { type: Boolean, required: true, skipCheck: true },
1720+
unknownUnionWithFunction: { type: Function, required: true, skipCheck: true }
17191721
},
17201722
setup(__props: any, { expose: __expose }) {
17211723
__expose();

packages/compiler-sfc/__tests__/compileScript.spec.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,8 @@ const emit = defineEmits(['a', 'b'])
10421042
unknown: UnknownType
10431043
unknownUnion: UnknownType | string
10441044
unknownIntersection: UnknownType & Object
1045+
unknownUnionWithBoolean: UnknownType | boolean
1046+
unknownUnionWithFunction: UnknownType | (() => any)
10451047
}>()
10461048
</script>`)
10471049
assertCode(content)
@@ -1093,7 +1095,13 @@ const emit = defineEmits(['a', 'b'])
10931095
expect(content).toMatch(`unknownUnion: { type: null, required: true }`)
10941096
// intersection containing unknown type: narrow to the known types
10951097
expect(content).toMatch(
1096-
`unknownIntersection: { type: Object, required: true }`
1098+
`unknownIntersection: { type: Object, required: true },`
1099+
)
1100+
expect(content).toMatch(
1101+
`unknownUnionWithBoolean: { type: Boolean, required: true, skipCheck: true },`
1102+
)
1103+
expect(content).toMatch(
1104+
`unknownUnionWithFunction: { type: Function, required: true, skipCheck: true }`
10971105
)
10981106
expect(bindings).toStrictEqual({
10991107
string: BindingTypes.PROPS,
@@ -1131,7 +1139,9 @@ const emit = defineEmits(['a', 'b'])
11311139
nonNull: BindingTypes.PROPS,
11321140
unknown: BindingTypes.PROPS,
11331141
unknownUnion: BindingTypes.PROPS,
1134-
unknownIntersection: BindingTypes.PROPS
1142+
unknownIntersection: BindingTypes.PROPS,
1143+
unknownUnionWithBoolean: BindingTypes.PROPS,
1144+
unknownUnionWithFunction: BindingTypes.PROPS
11351145
})
11361146
})
11371147

packages/compiler-sfc/src/compileScript.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -888,11 +888,11 @@ export function compileScript(
888888
}
889889
}
890890
891-
const { type, required } = props[key]
891+
const { type, required, skipCheck } = props[key]
892892
if (!isProd) {
893893
return `${key}: { type: ${toRuntimeTypeString(
894894
type
895-
)}, required: ${required}${
895+
)}, required: ${required}${skipCheck ? ', skipCheck: true' : ''}${
896896
defaultString ? `, ${defaultString}` : ``
897897
} }`
898898
} else if (
@@ -1964,6 +1964,7 @@ interface PropTypeData {
19641964
key: string
19651965
type: string[]
19661966
required: boolean
1967+
skipCheck: boolean
19671968
}
19681969

19691970
function recordType(node: Node, declaredTypes: Record<string, string[]>) {
@@ -1993,19 +1994,26 @@ function extractRuntimeProps(
19931994
m.key.type === 'Identifier'
19941995
) {
19951996
let type: string[] | undefined
1997+
let skipCheck = false
19961998
if (m.type === 'TSMethodSignature') {
19971999
type = ['Function']
19982000
} else if (m.typeAnnotation) {
19992001
type = inferRuntimeType(m.typeAnnotation.typeAnnotation, declaredTypes)
20002002
// skip check for result containing unknown types
20012003
if (type.includes(UNKNOWN_TYPE)) {
2002-
type = [`null`]
2004+
if (type.includes('Boolean') || type.includes('Function')) {
2005+
type = type.filter(t => t !== UNKNOWN_TYPE)
2006+
skipCheck = true
2007+
} else {
2008+
type = ['null']
2009+
}
20032010
}
20042011
}
20052012
props[m.key.name] = {
20062013
key: m.key.name,
20072014
required: !m.optional,
2008-
type: type || [`null`]
2015+
type: type || [`null`],
2016+
skipCheck
20092017
}
20102018
}
20112019
}

packages/runtime-core/__tests__/componentProps.spec.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,8 @@ describe('component props', () => {
335335
arr: { type: Array },
336336
obj: { type: Object },
337337
cls: { type: MyClass },
338-
fn: { type: Function }
338+
fn: { type: Function },
339+
skipCheck: { type: [Boolean, Function], skipCheck: true }
339340
},
340341
setup() {
341342
return () => null
@@ -349,7 +350,8 @@ describe('component props', () => {
349350
arr: {},
350351
obj: 'false',
351352
cls: {},
352-
fn: true
353+
fn: true,
354+
skipCheck: 'foo'
353355
}),
354356
nodeOps.createElement('div')
355357
)
@@ -374,6 +376,9 @@ describe('component props', () => {
374376
expect(
375377
`Invalid prop: type check failed for prop "cls". Expected MyClass, got Object`
376378
).toHaveBeenWarned()
379+
expect(
380+
`Invalid prop: type check failed for prop "skipCheck". Expected Boolean | Function, got String with value "foo".`
381+
).not.toHaveBeenWarned()
377382
})
378383

379384
// #3495

packages/runtime-core/src/componentProps.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export interface PropOptions<T = any, D = T> {
5858
required?: boolean
5959
default?: D | DefaultFactory<D> | null | undefined | object
6060
validator?(value: unknown): boolean
61+
skipCheck?: boolean
6162
}
6263

6364
export type PropType<T> = PropConstructor<T> | PropConstructor<T>[]
@@ -608,7 +609,7 @@ function validateProp(
608609
prop: PropOptions,
609610
isAbsent: boolean
610611
) {
611-
const { type, required, validator } = prop
612+
const { type, required, validator, skipCheck } = prop
612613
// required!
613614
if (required && isAbsent) {
614615
warn('Missing required prop: "' + name + '"')
@@ -619,7 +620,7 @@ function validateProp(
619620
return
620621
}
621622
// type check
622-
if (type != null && type !== true) {
623+
if (type != null && type !== true && !skipCheck) {
623624
let isValid = false
624625
const types = isArray(type) ? type : [type]
625626
const expectedTypes = []

0 commit comments

Comments
 (0)