diff --git a/packages-private/dts-test/defineComponent.test-d.tsx b/packages-private/dts-test/defineComponent.test-d.tsx index fda3ca4856c..b64fceaf2ea 100644 --- a/packages-private/dts-test/defineComponent.test-d.tsx +++ b/packages-private/dts-test/defineComponent.test-d.tsx @@ -1613,7 +1613,7 @@ describe('directive typing', () => { expectType(comp.directives!.vShow) }) -describe('expose typing', () => { +describe('expose typing w/ options object', () => { const Comp = defineComponent({ expose: ['a', 'b'], props: { @@ -1637,6 +1637,41 @@ describe('expose typing', () => { vm.c }) +describe('expose typing w/ setup function', () => { + const Comp = defineComponent( + ( + props: { some: String }, + { + expose, + }: SetupContext, + ) => { + const a = 1 + const b = '2' + const c = 3 + + expose({ a, b }) + + return () => h('div') + }, + { + props: ['some'], + expose: ['a', 'b'], + }, + ) + + expectType>(Comp.expose!) + + const vm = new Comp({ some: 'string' }) + // internal should still be exposed + vm.$props + + expectType(vm.a) + expectType(vm.b) + + // @ts-expect-error shouldn't be exposed + vm.c +}) + import type { AllowedComponentProps, ComponentCustomProps, diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index 2ce870f0141..23520c98ec7 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -118,6 +118,7 @@ export type DefineSetupFnComponent< S extends SlotsType = SlotsType, Props = P & EmitsToProps, PP = PublicProps, + Exposed extends string = string, > = new ( props: Props & PP, ) => CreateComponentPublicInstanceWithMixins< @@ -133,7 +134,10 @@ export type DefineSetupFnComponent< {}, false, {}, - S + S, + {}, + {}, + Exposed > type ToResolvedProps = Readonly & @@ -151,33 +155,51 @@ export function defineComponent< E extends EmitsOptions = {}, EE extends string = string, S extends SlotsType = {}, + Exposed extends Record = Record, >( setup: ( props: Props, - ctx: SetupContext, + ctx: SetupContext, ) => RenderFunction | Promise, - options?: Pick & { + options?: Pick & { props?: (keyof Props)[] emits?: E | EE[] slots?: S + expose?: (keyof Exposed)[] }, -): DefineSetupFnComponent +): DefineSetupFnComponent< + Props, + E, + S, + Props & EmitsToProps, + PublicProps, + Extract +> export function defineComponent< Props extends Record, E extends EmitsOptions = {}, EE extends string = string, S extends SlotsType = {}, + Exposed extends Record = Record, >( setup: ( props: Props, - ctx: SetupContext, + ctx: SetupContext, ) => RenderFunction | Promise, - options?: Pick & { + options?: Pick & { props?: ComponentObjectPropsOptions emits?: E | EE[] slots?: S + expose?: (keyof Exposed)[] }, -): DefineSetupFnComponent +): DefineSetupFnComponent< + Props, + E, + S, + Props & EmitsToProps, + PublicProps, + Extract +> // 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 3ed42ed0b55..60d53a14019 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -217,6 +217,7 @@ export interface FunctionalComponent< E extends EmitsOptions | Record = {}, S extends Record = any, EE extends EmitsOptions = ShortEmitsToObject, + Exposed extends Record = Record, > extends ComponentInternalOptions { // use of any here is intentional so it can be a valid JSX Element constructor ( @@ -226,6 +227,7 @@ export interface FunctionalComponent< props?: ComponentPropsOptions

emits?: EE | (keyof EE)[] slots?: IfAny> + expose?: (keyof Exposed)[] inheritAttrs?: boolean displayName?: string compatConfig?: CompatConfig @@ -278,14 +280,13 @@ export type LifecycleHook = (TFn & SchedulerJob)[] | null export type SetupContext< E = EmitsOptions, S extends SlotsType = {}, + EX extends Record = Record, > = E extends any ? { attrs: Data slots: UnwrapSlotsType emit: EmitFn - expose: = Record>( - exposed?: Exposed, - ) => void + expose: (exposed?: Exposed) => void } : never