From: Carlos Rodrigues Date: Fri, 8 Dec 2023 14:54:57 +0000 (+0000) Subject: fix(types): support for generic keyof slots (#8374) X-Git-Tag: v3.4.0-beta.1~23^2~13 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=213eba479ce080efc1053fe636f6be4a4c889b44;p=thirdparty%2Fvuejs%2Fcore.git fix(types): support for generic keyof slots (#8374) --- diff --git a/packages/dts-test/setupHelpers.test-d.ts b/packages/dts-test/setupHelpers.test-d.ts index 51f95c0094..53c4d85978 100644 --- a/packages/dts-test/setupHelpers.test-d.ts +++ b/packages/dts-test/setupHelpers.test-d.ts @@ -260,6 +260,30 @@ describe('defineSlots', () => { expectType(slotsUntype) }) +describe('defineSlots generic', >() => { + const props = defineProps<{ + item: T + }>() + + const slots = defineSlots< + { + [K in keyof T as `slot-${K & string}`]?: (props: { item: T }) => any + } & { + label?: (props: { item: T }) => any + } + >() + + for (const key of Object.keys(props.item) as (keyof T & string)[]) { + slots[`slot-${String(key)}`]?.({ + item: props.item + }) + } + slots.label?.({ item: props.item }) + + // @ts-expect-error calling wrong slot + slots.foo({}) +}) + describe('defineModel', () => { // overload 1 const modelValueRequired = defineModel({ required: true }) @@ -336,6 +360,78 @@ describe('useSlots', () => { expectType(slots) }) +describe('defineSlots generic', >() => { + const props = defineProps<{ + item: T + }>() + + const slots = defineSlots< + { + [K in keyof T as `slot-${K & string}`]?: (props: { item: T }) => any + } & { + label?: (props: { item: T }) => any + } + >() + + // @ts-expect-error slots should be readonly + slots.label = () => {} + + // @ts-expect-error non existing slot + slots['foo-asdas']?.({ + item: props.item + }) + for (const key in props.item) { + slots[`slot-${String(key)}`]?.({ + item: props.item + }) + slots[`slot-${String(key as keyof T)}`]?.({ + item: props.item + }) + } + + for (const key of Object.keys(props.item) as (keyof T)[]) { + slots[`slot-${String(key)}`]?.({ + item: props.item + }) + } + slots.label?.({ item: props.item }) + + // @ts-expect-error calling wrong slot + slots.foo({}) +}) + +describe('defineSlots generic strict', () => { + const props = defineProps<{ + item: T + }>() + + const slots = defineSlots< + { + [K in keyof T as `slot-${K & string}`]?: (props: { item: T }) => any + } & { + label?: (props: { item: T }) => any + } + >() + + // slot-bar/foo should be automatically inferred + slots['slot-bar']?.({ item: props.item }) + slots['slot-foo']?.({ item: props.item }) + + slots.label?.({ item: props.item }) + + // @ts-expect-error not part of the extends + slots['slot-RANDOM']?.({ item: props.item }) + + // @ts-expect-error slots should be readonly + slots.label = () => {} + + // @ts-expect-error calling wrong slot + slots.foo({}) +}) + // #6420 describe('toRefs w/ type declaration', () => { const props = defineProps<{ diff --git a/packages/runtime-core/src/componentSlots.ts b/packages/runtime-core/src/componentSlots.ts index 980ee79918..99936f49de 100644 --- a/packages/runtime-core/src/componentSlots.ts +++ b/packages/runtime-core/src/componentSlots.ts @@ -44,7 +44,7 @@ export type SlotsType = Record> = { export type StrictUnwrapSlotsType< S extends SlotsType, T = NonNullable -> = [keyof S] extends [never] ? Slots : Readonly +> = [keyof S] extends [never] ? Slots : Readonly & T export type UnwrapSlotsType< S extends SlotsType,