Skip to content

Commit 213eba4

Browse files
authored
fix(types): support for generic keyof slots (#8374)
1 parent 0d61b42 commit 213eba4

File tree

2 files changed

+97
-1
lines changed

2 files changed

+97
-1
lines changed

packages/dts-test/setupHelpers.test-d.ts

+96
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,30 @@ describe('defineSlots', () => {
260260
expectType<Slots>(slotsUntype)
261261
})
262262

263+
describe('defineSlots generic', <T extends Record<string, any>>() => {
264+
const props = defineProps<{
265+
item: T
266+
}>()
267+
268+
const slots = defineSlots<
269+
{
270+
[K in keyof T as `slot-${K & string}`]?: (props: { item: T }) => any
271+
} & {
272+
label?: (props: { item: T }) => any
273+
}
274+
>()
275+
276+
for (const key of Object.keys(props.item) as (keyof T & string)[]) {
277+
slots[`slot-${String(key)}`]?.({
278+
item: props.item
279+
})
280+
}
281+
slots.label?.({ item: props.item })
282+
283+
// @ts-expect-error calling wrong slot
284+
slots.foo({})
285+
})
286+
263287
describe('defineModel', () => {
264288
// overload 1
265289
const modelValueRequired = defineModel<boolean>({ required: true })
@@ -336,6 +360,78 @@ describe('useSlots', () => {
336360
expectType<Slots>(slots)
337361
})
338362

363+
describe('defineSlots generic', <T extends Record<string, any>>() => {
364+
const props = defineProps<{
365+
item: T
366+
}>()
367+
368+
const slots = defineSlots<
369+
{
370+
[K in keyof T as `slot-${K & string}`]?: (props: { item: T }) => any
371+
} & {
372+
label?: (props: { item: T }) => any
373+
}
374+
>()
375+
376+
// @ts-expect-error slots should be readonly
377+
slots.label = () => {}
378+
379+
// @ts-expect-error non existing slot
380+
slots['foo-asdas']?.({
381+
item: props.item
382+
})
383+
for (const key in props.item) {
384+
slots[`slot-${String(key)}`]?.({
385+
item: props.item
386+
})
387+
slots[`slot-${String(key as keyof T)}`]?.({
388+
item: props.item
389+
})
390+
}
391+
392+
for (const key of Object.keys(props.item) as (keyof T)[]) {
393+
slots[`slot-${String(key)}`]?.({
394+
item: props.item
395+
})
396+
}
397+
slots.label?.({ item: props.item })
398+
399+
// @ts-expect-error calling wrong slot
400+
slots.foo({})
401+
})
402+
403+
describe('defineSlots generic strict', <T extends {
404+
foo: 'foo'
405+
bar: 'bar'
406+
}>() => {
407+
const props = defineProps<{
408+
item: T
409+
}>()
410+
411+
const slots = defineSlots<
412+
{
413+
[K in keyof T as `slot-${K & string}`]?: (props: { item: T }) => any
414+
} & {
415+
label?: (props: { item: T }) => any
416+
}
417+
>()
418+
419+
// slot-bar/foo should be automatically inferred
420+
slots['slot-bar']?.({ item: props.item })
421+
slots['slot-foo']?.({ item: props.item })
422+
423+
slots.label?.({ item: props.item })
424+
425+
// @ts-expect-error not part of the extends
426+
slots['slot-RANDOM']?.({ item: props.item })
427+
428+
// @ts-expect-error slots should be readonly
429+
slots.label = () => {}
430+
431+
// @ts-expect-error calling wrong slot
432+
slots.foo({})
433+
})
434+
339435
// #6420
340436
describe('toRefs w/ type declaration', () => {
341437
const props = defineProps<{

packages/runtime-core/src/componentSlots.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export type SlotsType<T extends Record<string, any> = Record<string, any>> = {
4444
export type StrictUnwrapSlotsType<
4545
S extends SlotsType,
4646
T = NonNullable<S[typeof SlotSymbol]>
47-
> = [keyof S] extends [never] ? Slots : Readonly<T>
47+
> = [keyof S] extends [never] ? Slots : Readonly<T> & T
4848

4949
export type UnwrapSlotsType<
5050
S extends SlotsType,

0 commit comments

Comments
 (0)