vue-types
Version:
Prop types utility for Vue
75 lines (66 loc) • 2.17 kB
text/typescript
import { Prop, VueProp, VueTypeShape, VueTypeLooseShape } from '../types'
import { toType, validateType, warn, isPlainObject, indent } from '../utils'
// eslint-disable-next-line @typescript-eslint/ban-types
export default function shape<T extends object>(
obj: { [K in keyof T]: Prop<T[K]> | VueProp<T[K]> },
): VueTypeShape<T> {
const keys = Object.keys(obj)
const requiredKeys = keys.filter((key) => !!(obj as any)[key]?.required)
const type = toType('shape', {
type: Object,
validator(this: VueTypeShape<T> | VueTypeLooseShape<T>, value) {
if (!isPlainObject(value)) {
return false
}
const valueKeys = Object.keys(value)
// check for required keys (if any)
if (
requiredKeys.length > 0 &&
requiredKeys.some((req) => valueKeys.indexOf(req) === -1)
) {
const missing = requiredKeys.filter(
(req) => valueKeys.indexOf(req) === -1,
)
if (missing.length === 1) {
warn(`shape - required property "${missing[0]}" is not defined.`)
} else {
warn(
`shape - required properties "${missing.join(
'", "',
)}" are not defined.`,
)
}
return false
}
return valueKeys.every((key) => {
if (keys.indexOf(key) === -1) {
if ((this as VueTypeLooseShape<T>)._vueTypes_isLoose === true)
return true
warn(
`shape - shape definition does not include a "${key}" property. Allowed keys: "${keys.join(
'", "',
)}".`,
)
return false
}
const type = (obj as any)[key]
const valid = validateType(type, value[key], true)
if (typeof valid === 'string') {
warn(`shape - "${key}" property validation error:\n ${indent(valid)}`)
}
return valid === true
})
},
}) as VueTypeShape<T>
Object.defineProperty(type, '_vueTypes_isLoose', {
writable: true,
value: false,
})
Object.defineProperty(type, 'loose', {
get() {
this._vueTypes_isLoose = true
return this
},
})
return type
}