types(runtime-core): improve PropType inference precision (#1863)
This commit is contained in:
parent
4d51be73d3
commit
9d36c61796
@ -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,
|
||||||
|
@ -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']} />)
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user