Skip to content

Commit 216f269

Browse files
authored
fix(types): support generic usage with withDefaults + defineProps (#8335)
fix #8310 fix #8331 fix #8325
1 parent 91f1c62 commit 216f269

File tree

2 files changed

+64
-22
lines changed

2 files changed

+64
-22
lines changed

Diff for: packages/dts-test/setupHelpers.test-d.ts

+34
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,40 @@ describe('defineProps w/ union type declaration + withDefaults', () => {
100100
)
101101
})
102102

103+
describe('defineProps w/ generic type declaration + withDefaults', <T extends number, TA extends {
104+
a: string
105+
}, TString extends string>() => {
106+
const res = withDefaults(
107+
defineProps<{
108+
n?: number
109+
bool?: boolean
110+
111+
generic1?: T[] | { x: T }
112+
generic2?: { x: T }
113+
generic3?: TString
114+
generic4?: TA
115+
}>(),
116+
{
117+
n: 123,
118+
119+
generic1: () => [123, 33] as T[],
120+
generic2: () => ({ x: 123 } as { x: T }),
121+
122+
generic3: () => 'test' as TString,
123+
generic4: () => ({ a: 'test' } as TA)
124+
}
125+
)
126+
127+
res.n + 1
128+
129+
expectType<T[] | { x: T }>(res.generic1)
130+
expectType<{ x: T }>(res.generic2)
131+
expectType<TString>(res.generic3)
132+
expectType<TA>(res.generic4)
133+
134+
expectType<boolean>(res.bool)
135+
})
136+
103137
describe('defineProps w/ runtime declaration', () => {
104138
// runtime declaration
105139
const props = defineProps({

Diff for: packages/runtime-core/src/apiSetupHelpers.ts

+30-22
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@ export function defineProps<
8181
PP extends ComponentObjectPropsOptions = ComponentObjectPropsOptions
8282
>(props: PP): Prettify<Readonly<ExtractPropTypes<PP>>>
8383
// overload 3: typed-based declaration
84-
export function defineProps<TypeProps>(): DefineProps<TypeProps>
84+
export function defineProps<TypeProps>(): DefineProps<
85+
TypeProps,
86+
BooleanKey<TypeProps>
87+
>
8588
// implementation
8689
export function defineProps() {
8790
if (__DEV__) {
@@ -90,8 +93,8 @@ export function defineProps() {
9093
return null as any
9194
}
9295

93-
type DefineProps<T> = Readonly<T> & {
94-
readonly [K in BooleanKey<T>]-?: boolean
96+
type DefineProps<T, BKeys extends keyof T> = Readonly<T> & {
97+
readonly [K in BKeys]-?: boolean
9598
}
9699

97100
type BooleanKey<T, K extends keyof T = keyof T> = K extends any
@@ -281,26 +284,27 @@ interface DefineModelOptions {
281284
type NotUndefined<T> = T extends undefined ? never : T
282285

283286
type InferDefaults<T> = {
284-
[K in keyof T]?: InferDefault<T, NotUndefined<T[K]>>
287+
[K in keyof T]?: InferDefault<T, T[K]>
285288
}
286289

287-
type InferDefault<P, T> = T extends
288-
| null
289-
| number
290-
| string
291-
| boolean
292-
| symbol
293-
| Function
294-
? T | ((props: P) => T)
295-
: (props: P) => T
296-
297-
type PropsWithDefaults<Base, Defaults> = Base & {
298-
[K in keyof Defaults]: K extends keyof Base
290+
type NativeType = null | number | string | boolean | symbol | Function
291+
292+
type InferDefault<P, T> =
293+
| ((props: P) => T & {})
294+
| (T extends NativeType ? T : never)
295+
296+
type PropsWithDefaults<
297+
T,
298+
Defaults extends InferDefaults<T>,
299+
BKeys extends keyof T
300+
> = Omit<T, keyof Defaults> & {
301+
[K in keyof Defaults]-?: K extends keyof T
299302
? Defaults[K] extends undefined
300-
? Base[K]
301-
: NotUndefined<Base[K]>
303+
? T[K]
304+
: NotUndefined<T[K]>
302305
: never
303-
}
306+
} & { readonly [K in BKeys]-?: boolean }
307+
304308
/**
305309
* Vue `<script setup>` compiler macro for providing props default values when
306310
* using type-based `defineProps` declaration.
@@ -321,10 +325,14 @@ type PropsWithDefaults<Base, Defaults> = Base & {
321325
*
322326
* @see {@link https://vuejs.org/guide/typescript/composition-api.html#typing-component-props}
323327
*/
324-
export function withDefaults<Props, Defaults extends InferDefaults<Props>>(
325-
props: Props,
328+
export function withDefaults<
329+
T,
330+
BKeys extends keyof T,
331+
Defaults extends InferDefaults<T>
332+
>(
333+
props: DefineProps<T, BKeys>,
326334
defaults: Defaults
327-
): PropsWithDefaults<Props, Defaults> {
335+
): PropsWithDefaults<T, Defaults, BKeys> {
328336
if (__DEV__) {
329337
warnRuntimeUsage(`withDefaults`)
330338
}

0 commit comments

Comments
 (0)