From e4af9747dc17e5749c0ebf95409555cd0d89922d Mon Sep 17 00:00:00 2001 From: pikax Date: Fri, 19 May 2023 11:47:55 +0100 Subject: [PATCH 1/3] types(defineSlots): Support for generic keyof slots --- packages/dts-test/setupHelpers.test-d.ts | 24 +++++++++++++++++++++ packages/runtime-core/src/componentSlots.ts | 4 +++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/dts-test/setupHelpers.test-d.ts b/packages/dts-test/setupHelpers.test-d.ts index 77342590dc6..e9fb9bab262 100644 --- a/packages/dts-test/setupHelpers.test-d.ts +++ b/packages/dts-test/setupHelpers.test-d.ts @@ -232,6 +232,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 }) diff --git a/packages/runtime-core/src/componentSlots.ts b/packages/runtime-core/src/componentSlots.ts index afc5f03933b..675adf47691 100644 --- a/packages/runtime-core/src/componentSlots.ts +++ b/packages/runtime-core/src/componentSlots.ts @@ -41,11 +41,13 @@ export type SlotsType = Record> = { [SlotSymbol]?: T } -export type StrictUnwrapSlotsType< +export type StrictUnwrapSlotsTypeOld< S extends SlotsType, T = NonNullable > = [keyof S] extends [never] ? Slots : Readonly +export type StrictUnwrapSlotsType = S extends SlotsType ? T : Slots + export type UnwrapSlotsType< S extends SlotsType, T = NonNullable From 63787e1a91b6b1ee82f6ac9dfca97281006d3c19 Mon Sep 17 00:00:00 2001 From: pikax Date: Fri, 19 May 2023 12:26:27 +0100 Subject: [PATCH 2/3] rollback implementation --- packages/runtime-core/src/componentSlots.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/runtime-core/src/componentSlots.ts b/packages/runtime-core/src/componentSlots.ts index 675adf47691..307951274a4 100644 --- a/packages/runtime-core/src/componentSlots.ts +++ b/packages/runtime-core/src/componentSlots.ts @@ -41,12 +41,10 @@ export type SlotsType = Record> = { [SlotSymbol]?: T } -export type StrictUnwrapSlotsTypeOld< +export type StrictUnwrapSlotsType< S extends SlotsType, T = NonNullable -> = [keyof S] extends [never] ? Slots : Readonly - -export type StrictUnwrapSlotsType = S extends SlotsType ? T : Slots +> = [keyof S] extends [never] ? Slots : T export type UnwrapSlotsType< S extends SlotsType, From 270e91c2e393803ed6e59b35b2f3d6ce439d9c03 Mon Sep 17 00:00:00 2001 From: pikax Date: Fri, 6 Oct 2023 13:40:36 +0100 Subject: [PATCH 3/3] improve implementation --- packages/dts-test/setupHelpers.test-d.ts | 72 +++++++++++++++++++++ packages/runtime-core/src/componentSlots.ts | 2 +- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/packages/dts-test/setupHelpers.test-d.ts b/packages/dts-test/setupHelpers.test-d.ts index a186d5e390a..99963742f6b 100644 --- a/packages/dts-test/setupHelpers.test-d.ts +++ b/packages/dts-test/setupHelpers.test-d.ts @@ -352,3 +352,75 @@ describe('useSlots', () => { const slots = 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({}) +}) diff --git a/packages/runtime-core/src/componentSlots.ts b/packages/runtime-core/src/componentSlots.ts index 307951274a4..e6fb6a54fdb 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 : T +> = [keyof S] extends [never] ? Slots : Readonly & T export type UnwrapSlotsType< S extends SlotsType,