From e8f693eda65ecb7c45054eaf53664665bc47eec9 Mon Sep 17 00:00:00 2001 From: Carlos Rodrigues Date: Thu, 30 Nov 2023 15:29:57 +0000 Subject: [PATCH] types(defineComponent): Keep slot information on functional components --- packages/dts-test/defineComponent.test-d.tsx | 35 +++++++++++++++++++ .../runtime-core/src/apiDefineComponent.ts | 4 +-- packages/runtime-core/src/h.ts | 18 ++++++++-- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/packages/dts-test/defineComponent.test-d.tsx b/packages/dts-test/defineComponent.test-d.tsx index b3f735dda..a7c442146 100644 --- a/packages/dts-test/defineComponent.test-d.tsx +++ b/packages/dts-test/defineComponent.test-d.tsx @@ -1497,6 +1497,41 @@ describe('should work when props type is incompatible with setup returned type ' expectType(CompA.$props.size) }) +// #9649 +describe('should keep slots on functional component', () => { + const Comp = defineComponent( + ( + _1: {}, + _2: SetupContext< + {}, + SlotsType<{ default?(data: { foo: string; bar: number }): any }> + > + ) => + () => + null, + { + slots: Object as SlotsType<{ default: { foo: string; bar: number } }> + } + ) + + h(Comp, { + default: data => { + expectType<{ foo: string; bar: number }>(data) + // @ts-expect-error not any + expectType(data) + return null + } + }) + h(Comp, null, { + default: data => { + expectType<{ foo: string; bar: number }>(data) + // @ts-expect-error not any + expectType(data) + return null + } + }) +}) + import { DefineComponent, ComponentOptionsMixin, diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 092f679e9..5989b0c47 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -111,7 +111,7 @@ export function defineComponent< emits?: E | EE[] slots?: S } -): (props: Props & EmitsToProps) => any +): (props: Props & EmitsToProps & S) => any export function defineComponent< Props extends Record, E extends EmitsOptions = {}, @@ -127,7 +127,7 @@ export function defineComponent< emits?: E | EE[] slots?: S } -): (props: Props & EmitsToProps) => any +): (props: Props & EmitsToProps & S) => any // overload 2: object format with no props // (uses user defined props interface) diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index 4ca90262f..a232b9e6a 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -11,7 +11,7 @@ import { import { Teleport, TeleportProps } from './components/Teleport' import { Suspense, SuspenseProps } from './components/Suspense' import { isObject, isArray } from '@vue/shared' -import { RawSlots } from './componentSlots' +import { RawSlots, SlotsType, UnwrapSlotsType } from './componentSlots' import { FunctionalComponent, Component, @@ -119,6 +119,17 @@ export function h( children?: RawChildren | RawSlots ): VNode +// functional component +export function h< + P, + E extends EmitsOptions = {}, + S extends Record = {} +>( + type: FunctionalComponent, + children?: + | RawChildren + | (P extends SlotsType ? UnwrapSlotsType

: never) +): VNode // functional component export function h< P, @@ -127,7 +138,10 @@ export function h< >( type: FunctionalComponent, props?: (RawProps & P) | ({} extends P ? null : never), - children?: RawChildren | RawSlots + children?: + | RawChildren + | RawSlots + | (P extends SlotsType ? UnwrapSlotsType

: {}) ): VNode // catch-all for generic component types