diff --git a/packages-private/dts-test/defineComponent.test-d.tsx b/packages-private/dts-test/defineComponent.test-d.tsx index 6188b102b31..084bd44dcba 100644 --- a/packages-private/dts-test/defineComponent.test-d.tsx +++ b/packages-private/dts-test/defineComponent.test-d.tsx @@ -2,6 +2,7 @@ import { type Component, type ComponentOptions, type ComponentPublicInstance, + type EmitsOptions, type PropType, type SetupContext, type Slots, @@ -1175,6 +1176,73 @@ describe('componentOptions setup should be `SetupContext`', () => { ) }) +describe('infer slots from `SetupContext`', () => { + // options + const Foo = defineComponent({ + setup( + _props, + _ctx: SetupContext, + ) {}, + render() { + this.$slots.default({ foo: 1 }) + }, + }) + const foo = {} as InstanceType + expectType>(false) + foo.$slots.default({ foo: 1 }) + + const Bar = defineComponent({ + setup( + _props, + _ctx: { + slots: { + default: (props: { foo: number }) => VNode + } + }, + ) {}, + render() { + this.$slots.default({ foo: 1 }) + }, + }) + const bar = {} as InstanceType + expectType>(false) + bar.$slots.default({ foo: 1 }) + + // functional + const Baz = defineComponent( + ( + props: { foo: T }, + ctx: SetupContext< + EmitsOptions, + SlotsType<{ + default: (props: { foo: T }) => VNode + }> + >, + ) => + () => + ctx.slots.default(props), + ) + const baz = new Baz({ foo: 1 }) + expectType>(false) + baz.$slots.default({ foo: 1 }) + + const Qux = defineComponent( + ( + props: { foo: T }, + ctx: { + slots: { + default: (props: { foo: T }) => VNode + } + }, + ) => + () => + ctx.slots.default(props), + ) + const qux = new Qux({ foo: 1 }) + expectType>(false) + qux.$slots.default({ foo: 1 }) +}) + describe('extract instance type', () => { const Base = defineComponent({ props: { @@ -1750,7 +1818,6 @@ import type { ComponentOptionsMixin, DefineComponent, Directive, - EmitsOptions, ExtractPropTypes, KeepAliveProps, TransitionProps, diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 4865c3b4ea4..b18daf49dde 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -150,7 +150,7 @@ export function defineComponent< Props extends Record, E extends EmitsOptions = {}, EE extends string = string, - S extends SlotsType = {}, + S extends SlotsType | Record = {}, >( setup: ( props: Props, @@ -166,7 +166,7 @@ export function defineComponent< Props extends Record, E extends EmitsOptions = {}, EE extends string = string, - S extends SlotsType = {}, + S extends SlotsType | Record = {}, >( setup: ( props: Props, @@ -199,7 +199,7 @@ export function defineComponent< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, InjectOptions extends ComponentInjectOptions = {}, InjectKeys extends string = string, - Slots extends SlotsType = {}, + Slots extends SlotsType | Record = {}, LocalComponents extends Record = {}, Directives extends Record = {}, Exposed extends string = string, diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index c46741bee80..93847406d8f 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -287,11 +287,11 @@ export type LifecycleHook = (TFn & SchedulerJob)[] | null // use `E extends any` to force evaluating type to fix #2362 export type SetupContext< E = EmitsOptions, - S extends SlotsType = {}, + S extends SlotsType | Record = {}, > = E extends any ? { attrs: Attrs - slots: UnwrapSlotsType + slots: S extends SlotsType ? UnwrapSlotsType : Readonly emit: EmitFn expose: = Record>( exposed?: Exposed, diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index 8d3fdb056a9..68e9fd794c4 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -224,7 +224,7 @@ export type CreateComponentPublicInstanceWithMixins< Defaults = {}, MakeDefaultsOptional extends boolean = false, I extends ComponentInjectOptions = {}, - S extends SlotsType = {}, + S extends SlotsType | Record = {}, LC extends Record = {}, Directives extends Record = {}, Exposed extends string = string, @@ -272,7 +272,7 @@ export type CreateComponentPublicInstanceWithMixins< Provide >, I, - S, + S extends SlotsType ? S : SlotsType, Exposed, TypeRefs, TypeEl