refactor(utils): improve defineProps (#3811)

* refactor(utils): improve defineProps

* refactor(utils): improve defineProps
This commit is contained in:
三咲智子
2021-10-08 14:58:48 +08:00
committed by GitHub
parent 4281c49ff0
commit 4e458fe586
2 changed files with 86 additions and 12 deletions

View File

@@ -20,7 +20,8 @@ type ResolvePropTypeWithReadonly<T> = Readonly<T> extends Readonly<
>
? ResolvePropType<A[]>
: ResolvePropType<T>
type IfUnknown<T, V> = [unknown] extends T ? V : T
type IfUnknown<T, V> = [unknown] extends [T] ? V : T
export type BuildPropOption<T, D extends BuildPropType<T, V, C>, R, V, C> = {
type?: T
@@ -30,7 +31,7 @@ export type BuildPropOption<T, D extends BuildPropType<T, V, C>, R, V, C> = {
? never
: D extends Record<string, unknown> | Array<any>
? () => D
: D
: (() => D) | D
validator?: ((val: any) => val is C) | ((val: any) => boolean)
}
@@ -48,22 +49,32 @@ export type BuildPropType<T, V, C> = _BuildPropType<
IfUnknown<C, never>
>
export type BuildPropDefault<D, R> = R extends true
type _BuildPropDefault<T, D> = [T] extends [
// eslint-disable-next-line @typescript-eslint/ban-types
Record<string, unknown> | Array<any> | Function
]
? D
: D extends () => T
? ReturnType<D>
: D
export type BuildPropDefault<T, D, R> = R extends true
? { readonly default?: undefined }
: {
readonly default: Exclude<D, undefined> extends never
? undefined
: Exclude<
D extends Record<string, unknown> | Array<any> ? () => D : D,
undefined
>
: Exclude<_BuildPropDefault<T, D>, undefined>
}
export type BuildPropReturn<T, D, R, V, C> = {
readonly type: PropType<BuildPropType<T, V, C>>
readonly required: IfUnknown<R, false>
readonly validator: ((val: unknown) => boolean) | undefined
[propKey]: true
} & BuildPropDefault<IfUnknown<D, never>, IfUnknown<R, false>>
} & BuildPropDefault<
BuildPropType<T, V, C>,
IfUnknown<D, never>,
IfUnknown<R, false>
>
/**
* @description Build prop. It can better optimize prop types

View File

@@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/ban-types */
import { expectTypeOf } from 'expect-type'
import { buildProp, definePropType, mutable, keyOf, buildProps } from '../props'
import type { propKey } from '../props'
@@ -103,7 +105,7 @@ describe('buildProp', () => {
).toEqualTypeOf<{
readonly type: PropType<string[]>
readonly required: false
readonly default: () => ['a', 'b']
readonly default: ['a', 'b']
readonly validator: ((val: unknown) => boolean) | undefined
[propKey]: true
}>()
@@ -122,7 +124,7 @@ describe('buildProp', () => {
).toEqualTypeOf<{
readonly type: PropType<Options>
readonly required: false
readonly default: () => { key: 'value' }
readonly default: { key: 'value' }
readonly validator: ((val: unknown) => boolean) | undefined
[propKey]: true
}>()
@@ -141,7 +143,7 @@ describe('buildProp', () => {
).toEqualTypeOf<{
readonly type: PropType<string | Options>
readonly required: false
readonly default: () => { key: string }
readonly default: { key: string }
readonly validator: ((val: unknown) => boolean) | undefined
[propKey]: true
}>()
@@ -241,7 +243,7 @@ describe('buildProp', () => {
).toEqualTypeOf<{
readonly type: PropType<{ key: 'a' | 'b' | 'c' } | undefined>
readonly required: false
readonly default: () => { key: 'a' }
readonly default: { key: 'a' }
readonly validator: ((val: unknown) => boolean) | undefined
[propKey]: true
}>()
@@ -262,6 +264,21 @@ describe('buildProp', () => {
}>()
})
it('default value is empty object', () => {
expectTypeOf(
buildProp({
type: Object,
default: () => mutable({} as const),
} as const)
).toEqualTypeOf<{
readonly type: PropType<Record<string, any>>
readonly required: false
readonly default: {}
readonly validator: ((val: unknown) => boolean) | undefined
[propKey]: true
}>()
})
it('extract', () => {
const props = {
key1: buildProp({
@@ -318,6 +335,24 @@ describe('buildProps', () => {
key12: buildProp({
type: String,
} as const),
// default generator
key13: {
type: [String, Number, Function],
default: () => '123' as const,
} as const,
key14: {
type: Function,
default: () => '123' as const,
} as const,
key15: {
type: Function,
default: () => () => '123' as const,
} as const,
key16: {
type: String,
default: () => '123' as const,
} as const,
} as const)
expectTypeOf(props).toEqualTypeOf<{
@@ -371,6 +406,34 @@ describe('buildProps', () => {
readonly validator: ((val: unknown) => boolean) | undefined
[propKey]: true
}
readonly key13: {
readonly type: PropType<string | number | Function>
readonly required: false
readonly default: '123'
readonly validator: ((val: unknown) => boolean) | undefined
[propKey]: true
}
readonly key14: {
readonly type: PropType<Function>
readonly required: false
readonly default: () => '123'
readonly validator: ((val: unknown) => boolean) | undefined
[propKey]: true
}
readonly key15: {
readonly type: PropType<Function>
readonly required: false
readonly default: () => () => '123'
readonly validator: ((val: unknown) => boolean) | undefined
[propKey]: true
}
readonly key16: {
readonly type: PropType<string>
readonly required: false
readonly default: '123'
readonly validator: ((val: unknown) => boolean) | undefined
[propKey]: true
}
}>()
})
})