mirror of https://github.com/vuejs/core.git
fix(types): support generic usage with withDefaults + defineProps (#8335)
fix #8310 fix #8331 fix #8325
This commit is contained in:
parent
91f1c62e63
commit
216f26995b
|
@ -100,6 +100,40 @@ describe('defineProps w/ union type declaration + withDefaults', () => {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('defineProps w/ generic type declaration + withDefaults', <T extends number, TA extends {
|
||||||
|
a: string
|
||||||
|
}, TString extends string>() => {
|
||||||
|
const res = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
n?: number
|
||||||
|
bool?: boolean
|
||||||
|
|
||||||
|
generic1?: T[] | { x: T }
|
||||||
|
generic2?: { x: T }
|
||||||
|
generic3?: TString
|
||||||
|
generic4?: TA
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
n: 123,
|
||||||
|
|
||||||
|
generic1: () => [123, 33] as T[],
|
||||||
|
generic2: () => ({ x: 123 } as { x: T }),
|
||||||
|
|
||||||
|
generic3: () => 'test' as TString,
|
||||||
|
generic4: () => ({ a: 'test' } as TA)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
res.n + 1
|
||||||
|
|
||||||
|
expectType<T[] | { x: T }>(res.generic1)
|
||||||
|
expectType<{ x: T }>(res.generic2)
|
||||||
|
expectType<TString>(res.generic3)
|
||||||
|
expectType<TA>(res.generic4)
|
||||||
|
|
||||||
|
expectType<boolean>(res.bool)
|
||||||
|
})
|
||||||
|
|
||||||
describe('defineProps w/ runtime declaration', () => {
|
describe('defineProps w/ runtime declaration', () => {
|
||||||
// runtime declaration
|
// runtime declaration
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
|
|
@ -81,7 +81,10 @@ export function defineProps<
|
||||||
PP extends ComponentObjectPropsOptions = ComponentObjectPropsOptions
|
PP extends ComponentObjectPropsOptions = ComponentObjectPropsOptions
|
||||||
>(props: PP): Prettify<Readonly<ExtractPropTypes<PP>>>
|
>(props: PP): Prettify<Readonly<ExtractPropTypes<PP>>>
|
||||||
// overload 3: typed-based declaration
|
// overload 3: typed-based declaration
|
||||||
export function defineProps<TypeProps>(): DefineProps<TypeProps>
|
export function defineProps<TypeProps>(): DefineProps<
|
||||||
|
TypeProps,
|
||||||
|
BooleanKey<TypeProps>
|
||||||
|
>
|
||||||
// implementation
|
// implementation
|
||||||
export function defineProps() {
|
export function defineProps() {
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
|
@ -90,8 +93,8 @@ export function defineProps() {
|
||||||
return null as any
|
return null as any
|
||||||
}
|
}
|
||||||
|
|
||||||
type DefineProps<T> = Readonly<T> & {
|
type DefineProps<T, BKeys extends keyof T> = Readonly<T> & {
|
||||||
readonly [K in BooleanKey<T>]-?: boolean
|
readonly [K in BKeys]-?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type BooleanKey<T, K extends keyof T = keyof T> = K extends any
|
type BooleanKey<T, K extends keyof T = keyof T> = K extends any
|
||||||
|
@ -281,26 +284,27 @@ interface DefineModelOptions {
|
||||||
type NotUndefined<T> = T extends undefined ? never : T
|
type NotUndefined<T> = T extends undefined ? never : T
|
||||||
|
|
||||||
type InferDefaults<T> = {
|
type InferDefaults<T> = {
|
||||||
[K in keyof T]?: InferDefault<T, NotUndefined<T[K]>>
|
[K in keyof T]?: InferDefault<T, T[K]>
|
||||||
}
|
}
|
||||||
|
|
||||||
type InferDefault<P, T> = T extends
|
type NativeType = null | number | string | boolean | symbol | Function
|
||||||
| null
|
|
||||||
| number
|
|
||||||
| string
|
|
||||||
| boolean
|
|
||||||
| symbol
|
|
||||||
| Function
|
|
||||||
? T | ((props: P) => T)
|
|
||||||
: (props: P) => T
|
|
||||||
|
|
||||||
type PropsWithDefaults<Base, Defaults> = Base & {
|
type InferDefault<P, T> =
|
||||||
[K in keyof Defaults]: K extends keyof Base
|
| ((props: P) => T & {})
|
||||||
|
| (T extends NativeType ? T : never)
|
||||||
|
|
||||||
|
type PropsWithDefaults<
|
||||||
|
T,
|
||||||
|
Defaults extends InferDefaults<T>,
|
||||||
|
BKeys extends keyof T
|
||||||
|
> = Omit<T, keyof Defaults> & {
|
||||||
|
[K in keyof Defaults]-?: K extends keyof T
|
||||||
? Defaults[K] extends undefined
|
? Defaults[K] extends undefined
|
||||||
? Base[K]
|
? T[K]
|
||||||
: NotUndefined<Base[K]>
|
: NotUndefined<T[K]>
|
||||||
: never
|
: never
|
||||||
}
|
} & { readonly [K in BKeys]-?: boolean }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vue `<script setup>` compiler macro for providing props default values when
|
* Vue `<script setup>` compiler macro for providing props default values when
|
||||||
* using type-based `defineProps` declaration.
|
* using type-based `defineProps` declaration.
|
||||||
|
@ -321,10 +325,14 @@ type PropsWithDefaults<Base, Defaults> = Base & {
|
||||||
*
|
*
|
||||||
* @see {@link https://vuejs.org/guide/typescript/composition-api.html#typing-component-props}
|
* @see {@link https://vuejs.org/guide/typescript/composition-api.html#typing-component-props}
|
||||||
*/
|
*/
|
||||||
export function withDefaults<Props, Defaults extends InferDefaults<Props>>(
|
export function withDefaults<
|
||||||
props: Props,
|
T,
|
||||||
|
BKeys extends keyof T,
|
||||||
|
Defaults extends InferDefaults<T>
|
||||||
|
>(
|
||||||
|
props: DefineProps<T, BKeys>,
|
||||||
defaults: Defaults
|
defaults: Defaults
|
||||||
): PropsWithDefaults<Props, Defaults> {
|
): PropsWithDefaults<T, Defaults, BKeys> {
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
warnRuntimeUsage(`withDefaults`)
|
warnRuntimeUsage(`withDefaults`)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue