refactor: improve buildProp (#3592)

This commit is contained in:
三咲智子
2021-09-23 20:06:07 +08:00
committed by GitHub
parent f21b15a67e
commit 6f5ef560ea
2 changed files with 65 additions and 40 deletions

View File

@@ -64,6 +64,30 @@ export function buildProp<
: D
validator?: ((val: any) => val is C) | ((val: any) => boolean)
} = {}) {
const _validator =
values || validator
? (val: unknown) => {
let valid = false
let allowedValues: unknown[] = []
if (values) {
allowedValues = [...values, defaultValue]
valid ||= allowedValues.includes(val)
}
if (validator) valid ||= validator(val)
if (!valid && allowedValues.length > 0) {
debugWarn(
`Vue warn`,
`Invalid prop: Expected one of (${allowedValues.join(
', '
)}), got value ${val}`
)
}
return valid
}
: undefined
type HasDefaultValue = Exclude<D, undefined> extends never ? false : true
type Type = PropType<
| (T extends PropWrapper<unknown>
@@ -76,42 +100,24 @@ export function buildProp<
>
return {
type: ((type as any)?.[wrapperKey] || type) as unknown as Type,
required: !!required as R,
default: defaultValue as unknown as R extends true
? never
: HasDefaultValue extends true
? Exclude<
D extends Record<string, unknown> | Array<any> ? () => D : D,
undefined
>
: undefined,
validator:
values || validator
? (val: unknown) => {
let valid = false
let allowedValues: unknown[] = []
if (values) {
allowedValues = [...values, defaultValue]
valid ||= allowedValues.includes(val)
}
if (validator) valid ||= validator(val)
if (!valid && allowedValues.length > 0) {
debugWarn(
`Vue warn`,
`Invalid prop: Expected one of (${allowedValues.join(
', '
)}), got value ${val}`
)
}
return valid
}
: undefined,
} as const
type: (type as any)?.[wrapperKey] || type,
required: !!required,
default: defaultValue,
validator: _validator,
} as unknown as {
readonly type: Type
readonly required: R
readonly validator: typeof _validator
} & (R extends true
? { readonly default?: undefined }
: {
readonly default: HasDefaultValue extends true
? Exclude<
D extends Record<string, unknown> | Array<any> ? () => D : D,
undefined
>
: undefined
})
}
export const definePropType = <T>(val: any) =>

View File

@@ -1,7 +1,7 @@
import { expectTypeOf } from 'expect-type'
import { buildProp, definePropType, mutable, keyOf } from '../props'
import type { PropType } from 'vue'
import type { PropType, ExtractPropTypes } from 'vue'
describe('buildProp', () => {
it('Only type', () => {
@@ -67,7 +67,7 @@ describe('buildProp', () => {
).toEqualTypeOf<{
readonly type: PropType<'a' | 'b' | 'c'>
readonly required: true
readonly default: never
readonly default?: undefined
readonly validator: ((val: unknown) => boolean) | undefined
}>()
})
@@ -147,7 +147,7 @@ describe('buildProp', () => {
).toEqualTypeOf<{
readonly type: PropType<number | 'a' | 'b' | 'c'>
readonly required: true
readonly default: never
readonly default?: undefined
readonly validator: ((val: unknown) => boolean) | undefined
}>()
})
@@ -197,7 +197,7 @@ describe('buildProp', () => {
).toEqualTypeOf<{
readonly type: PropType<string>
readonly required: true
readonly default: never
readonly default?: undefined
readonly validator: ((val: unknown) => boolean) | undefined
}>()
})
@@ -243,4 +243,23 @@ describe('buildProp', () => {
readonly validator: ((val: unknown) => boolean) | undefined
}>()
})
it('extract', () => {
const props = {
key1: buildProp({
type: String,
required: true,
}),
key2: buildProp({
type: [String, Number],
required: true,
}),
} as const
type Extracted = ExtractPropTypes<typeof props>
expectTypeOf<Extracted>().toEqualTypeOf<{
readonly key1: string
readonly key2: string | number
}>()
})
})