diff --git a/packages-private/dts-test/defineComponent.test-d.tsx b/packages-private/dts-test/defineComponent.test-d.tsx index 6188b102b31..ff62aabb072 100644 --- a/packages-private/dts-test/defineComponent.test-d.tsx +++ b/packages-private/dts-test/defineComponent.test-d.tsx @@ -3,6 +3,7 @@ import { type ComponentOptions, type ComponentPublicInstance, type PropType, + type Ref, type SetupContext, type Slots, type SlotsType, @@ -12,6 +13,7 @@ import { h, reactive, ref, + shallowRef, withKeys, withModifiers, } from 'vue' @@ -1175,6 +1177,37 @@ describe('componentOptions setup should be `SetupContext`', () => { ) }) +describe('infer expose from `SetupContext`', () => { + // functional + const Baz = defineComponent( + ( + props: { foo: T }, + ctx: SetupContext }>, + ) => { + ctx.expose({ bar: shallowRef(props.foo) }) + return () => <> + }, + ) + const baz = new Baz({ foo: 1 }) + expectType>(false) + expectType(baz.bar) + + const Qux = defineComponent( + ( + props: { foo: T }, + ctx: { + expose: (exposed: { bar: Ref }) => void + }, + ) => { + ctx.expose({ bar: shallowRef(props.foo) }) + return () => <> + }, + ) + const qux = new Qux({ foo: 1 }) + expectType>(false) + expectType(qux.bar) +}) + describe('extract instance type', () => { const Base = defineComponent({ props: { diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 4865c3b4ea4..c36ea106a5e 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -116,13 +116,14 @@ export type DefineSetupFnComponent< P extends Record, E extends EmitsOptions = {}, S extends SlotsType = SlotsType, + B extends Record = {}, Props = P & EmitsToProps, PP = PublicProps, > = new ( props: Props & PP, ) => CreateComponentPublicInstanceWithMixins< Props, - {}, + B, {}, {}, {}, @@ -151,33 +152,35 @@ export function defineComponent< E extends EmitsOptions = {}, EE extends string = string, S extends SlotsType = {}, + B extends Record = {}, >( setup: ( props: Props, - ctx: SetupContext, + ctx: SetupContext, ) => RenderFunction | Promise, options?: Pick & { props?: (keyof NoInfer)[] emits?: E | EE[] slots?: S }, -): DefineSetupFnComponent +): DefineSetupFnComponent export function defineComponent< Props extends Record, E extends EmitsOptions = {}, EE extends string = string, S extends SlotsType = {}, + B extends Record = {}, >( setup: ( props: Props, - ctx: SetupContext, + ctx: SetupContext, ) => RenderFunction | Promise, options?: Pick & { props?: ComponentObjectPropsOptions emits?: E | EE[] slots?: S }, -): DefineSetupFnComponent +): DefineSetupFnComponent // overload 2: defineComponent with options object, infer props from options export function defineComponent< diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index c46741bee80..ae989102f60 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -288,14 +288,13 @@ export type LifecycleHook = (TFn & SchedulerJob)[] | null export type SetupContext< E = EmitsOptions, S extends SlotsType = {}, + Exposed extends Record = Record, > = E extends any ? { attrs: Attrs slots: UnwrapSlotsType emit: EmitFn - expose: = Record>( - exposed?: Exposed, - ) => void + expose: (exposed?: Exposed) => void } : never