types(runtime-core): improve PropType inference precision (#1863)

This commit is contained in:
HcySunYang 2020-08-18 23:23:18 +08:00 committed by GitHub
parent 4d51be73d3
commit 9d36c61796
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 18 additions and 4 deletions

View File

@ -40,14 +40,14 @@ export type ComponentObjectPropsOptions<P = Data> = {
[K in keyof P]: Prop<P[K]> | null [K in keyof P]: Prop<P[K]> | null
} }
export type Prop<T> = PropOptions<T> | PropType<T> export type Prop<T, D = T> = PropOptions<T, D> | PropType<T>
type DefaultFactory<T> = () => T | null | undefined type DefaultFactory<T> = () => T | null | undefined
interface PropOptions<T = any> { interface PropOptions<T = any, D = T> {
type?: PropType<T> | true | null type?: PropType<T> | true | null
required?: boolean required?: boolean
default?: T | DefaultFactory<T> | null | undefined default?: D | DefaultFactory<D> | null | undefined
validator?(value: unknown): boolean validator?(value: unknown): boolean
} }
@ -83,7 +83,7 @@ type InferPropType<T> = T extends null
? Record<string, any> ? Record<string, any>
: T extends BooleanConstructor | { type: BooleanConstructor } : T extends BooleanConstructor | { type: BooleanConstructor }
? boolean ? boolean
: T extends Prop<infer V> ? V : T : T extends Prop<infer V, infer D> ? (unknown extends V ? D : V) : T
export type ExtractPropTypes< export type ExtractPropTypes<
O, O,

View File

@ -27,6 +27,7 @@ describe('with object props', () => {
eee: () => { a: string } eee: () => { a: string }
fff: (a: number, b: string) => { a: boolean } fff: (a: number, b: string) => { a: boolean }
hhh: boolean hhh: boolean
ggg: 'foo' | 'bar'
validated?: string validated?: string
} }
@ -77,6 +78,11 @@ describe('with object props', () => {
type: Boolean, type: Boolean,
required: true required: true
}, },
// default + type casting
ggg: {
type: String as PropType<'foo' | 'bar'>,
default: 'foo'
},
validated: { validated: {
type: String, type: String,
validator: (val: unknown) => val !== '' validator: (val: unknown) => val !== ''
@ -97,6 +103,7 @@ describe('with object props', () => {
expectType<ExpectedProps['eee']>(props.eee) expectType<ExpectedProps['eee']>(props.eee)
expectType<ExpectedProps['fff']>(props.fff) expectType<ExpectedProps['fff']>(props.fff)
expectType<ExpectedProps['hhh']>(props.hhh) expectType<ExpectedProps['hhh']>(props.hhh)
expectType<ExpectedProps['ggg']>(props.ggg)
expectType<ExpectedProps['validated']>(props.validated) expectType<ExpectedProps['validated']>(props.validated)
// @ts-expect-error props should be readonly // @ts-expect-error props should be readonly
@ -128,6 +135,7 @@ describe('with object props', () => {
expectType<ExpectedProps['eee']>(props.eee) expectType<ExpectedProps['eee']>(props.eee)
expectType<ExpectedProps['fff']>(props.fff) expectType<ExpectedProps['fff']>(props.fff)
expectType<ExpectedProps['hhh']>(props.hhh) expectType<ExpectedProps['hhh']>(props.hhh)
expectType<ExpectedProps['ggg']>(props.ggg)
// @ts-expect-error props should be readonly // @ts-expect-error props should be readonly
expectError((props.a = 1)) expectError((props.a = 1))
@ -146,6 +154,7 @@ describe('with object props', () => {
expectType<ExpectedProps['eee']>(this.eee) expectType<ExpectedProps['eee']>(this.eee)
expectType<ExpectedProps['fff']>(this.fff) expectType<ExpectedProps['fff']>(this.fff)
expectType<ExpectedProps['hhh']>(this.hhh) expectType<ExpectedProps['hhh']>(this.hhh)
expectType<ExpectedProps['ggg']>(this.ggg)
// @ts-expect-error props on `this` should be readonly // @ts-expect-error props on `this` should be readonly
expectError((this.a = 1)) expectError((this.a = 1))
@ -177,6 +186,7 @@ describe('with object props', () => {
eee={() => ({ a: 'eee' })} eee={() => ({ a: 'eee' })}
fff={(a, b) => ({ a: a > +b })} fff={(a, b) => ({ a: a > +b })}
hhh={false} hhh={false}
ggg="foo"
// should allow class/style as attrs // should allow class/style as attrs
class="bar" class="bar"
style={{ color: 'red' }} style={{ color: 'red' }}
@ -194,6 +204,10 @@ describe('with object props', () => {
// @ts-expect-error wrong prop types // @ts-expect-error wrong prop types
<MyComponent a={'wrong type'} b="foo" dd={{ n: 1 }} ddd={['foo']} /> <MyComponent a={'wrong type'} b="foo" dd={{ n: 1 }} ddd={['foo']} />
) )
expectError(
// @ts-expect-error wrong prop types
<MyComponent ggg="baz" />
)
// @ts-expect-error // @ts-expect-error
expectError(<MyComponent b="foo" dd={{ n: 'string' }} ddd={['foo']} />) expectError(<MyComponent b="foo" dd={{ n: 'string' }} ddd={['foo']} />)
}) })