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();
unknown: UnknownType
unknownUnion: UnknownType | string
unknownIntersection: UnknownType & Object
+ unknownUnionWithBoolean: UnknownType | boolean
+ unknownUnionWithFunction: UnknownType | (() => any)
}>()
</script>`)
assertCode(content)
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,
nonNull: BindingTypes.PROPS,
unknown: BindingTypes.PROPS,
unknownUnion: BindingTypes.PROPS,
- unknownIntersection: BindingTypes.PROPS
+ unknownIntersection: BindingTypes.PROPS,
+ unknownUnionWithBoolean: BindingTypes.PROPS,
+ unknownUnionWithFunction: BindingTypes.PROPS
})
})
}
}
- 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 (
key: string
type: string[]
required: boolean
+ skipCheck: boolean
}
function recordType(node: Node, declaredTypes: Record<string, string[]>) {
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
}
}
}
arr: { type: Array },
obj: { type: Object },
cls: { type: MyClass },
- fn: { type: Function }
+ fn: { type: Function },
+ skipCheck: { type: [Boolean, Function], skipCheck: true }
},
setup() {
return () => null
arr: {},
obj: 'false',
cls: {},
- fn: true
+ fn: true,
+ skipCheck: 'foo'
}),
nodeOps.createElement('div')
)
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
required?: boolean
default?: D | DefaultFactory<D> | null | undefined | object
validator?(value: unknown): boolean
+ skipCheck?: boolean
}
export type PropType<T> = PropConstructor<T> | PropConstructor<T>[]
prop: PropOptions,
isAbsent: boolean
) {
- const { type, required, validator } = prop
+ const { type, required, validator, skipCheck } = prop
// required!
if (required && isAbsent) {
warn('Missing required prop: "' + name + '"')
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 = []