Skip to content

feat(types): Add Exposed template to SetupContext #13177

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
37 changes: 36 additions & 1 deletion packages-private/dts-test/defineComponent.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1613,7 +1613,7 @@ describe('directive typing', () => {
expectType<typeof vShow>(comp.directives!.vShow)
})

describe('expose typing', () => {
describe('expose typing w/ options object', () => {
const Comp = defineComponent({
expose: ['a', 'b'],
props: {
Expand All @@ -1637,6 +1637,41 @@ describe('expose typing', () => {
vm.c
})

describe('expose typing w/ setup function', () => {
const Comp = defineComponent(
(
props: { some: String },
{
expose,
}: SetupContext<EmitsOptions, SlotsType, { a: number; b: string }>,
) => {
const a = 1
const b = '2'
const c = 3

expose({ a, b })

return () => h('div')
},
{
props: ['some'],
expose: ['a', 'b'],
},
)

expectType<Array<'a' | 'b'>>(Comp.expose!)

const vm = new Comp({ some: 'string' })
// internal should still be exposed
vm.$props

expectType<number>(vm.a)
expectType<string>(vm.b)

// @ts-expect-error shouldn't be exposed
vm.c
})

import type {
AllowedComponentProps,
ComponentCustomProps,
Expand Down
36 changes: 29 additions & 7 deletions packages/runtime-core/src/apiDefineComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export type DefineSetupFnComponent<
S extends SlotsType = SlotsType,
Props = P & EmitsToProps<E>,
PP = PublicProps,
Exposed extends string = string,
> = new (
props: Props & PP,
) => CreateComponentPublicInstanceWithMixins<
Expand All @@ -133,7 +134,10 @@ export type DefineSetupFnComponent<
{},
false,
{},
S
S,
{},
{},
Exposed
>

type ToResolvedProps<Props, Emits extends EmitsOptions> = Readonly<Props> &
Expand All @@ -151,33 +155,51 @@ export function defineComponent<
E extends EmitsOptions = {},
EE extends string = string,
S extends SlotsType = {},
Exposed extends Record<string, any> = Record<string, any>,
>(
setup: (
props: Props,
ctx: SetupContext<E, S>,
ctx: SetupContext<E, S, Exposed>,
) => RenderFunction | Promise<RenderFunction>,
options?: Pick<ComponentOptions, 'name' | 'inheritAttrs'> & {
options?: Pick<ComponentOptions, 'name' | 'inheritAttrs' | 'expose'> & {
props?: (keyof Props)[]
emits?: E | EE[]
slots?: S
expose?: (keyof Exposed)[]
},
): DefineSetupFnComponent<Props, E, S>
): DefineSetupFnComponent<
Props,
E,
S,
Props & EmitsToProps<E>,
PublicProps,
Extract<keyof Exposed, string>
>
export function defineComponent<
Props extends Record<string, any>,
E extends EmitsOptions = {},
EE extends string = string,
S extends SlotsType = {},
Exposed extends Record<string, any> = Record<string, any>,
>(
setup: (
props: Props,
ctx: SetupContext<E, S>,
ctx: SetupContext<E, S, Exposed>,
) => RenderFunction | Promise<RenderFunction>,
options?: Pick<ComponentOptions, 'name' | 'inheritAttrs'> & {
options?: Pick<ComponentOptions, 'name' | 'inheritAttrs' | 'expose'> & {
props?: ComponentObjectPropsOptions<Props>
emits?: E | EE[]
slots?: S
expose?: (keyof Exposed)[]
},
): DefineSetupFnComponent<Props, E, S>
): DefineSetupFnComponent<
Props,
E,
S,
Props & EmitsToProps<E>,
PublicProps,
Extract<keyof Exposed, string>
>

// overload 2: defineComponent with options object, infer props from options
export function defineComponent<
Expand Down
7 changes: 4 additions & 3 deletions packages/runtime-core/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ export interface FunctionalComponent<
E extends EmitsOptions | Record<string, any[]> = {},
S extends Record<string, any> = any,
EE extends EmitsOptions = ShortEmitsToObject<E>,
Exposed extends Record<string, any> = Record<string, any>,
> extends ComponentInternalOptions {
// use of any here is intentional so it can be a valid JSX Element constructor
(
Expand All @@ -226,6 +227,7 @@ export interface FunctionalComponent<
props?: ComponentPropsOptions<P>
emits?: EE | (keyof EE)[]
slots?: IfAny<S, Slots, SlotsType<S>>
expose?: (keyof Exposed)[]
inheritAttrs?: boolean
displayName?: string
compatConfig?: CompatConfig
Expand Down Expand Up @@ -278,14 +280,13 @@ export type LifecycleHook<TFn = Function> = (TFn & SchedulerJob)[] | null
export type SetupContext<
E = EmitsOptions,
S extends SlotsType = {},
EX extends Record<string, any> = Record<string, any>,
> = E extends any
? {
attrs: Data
slots: UnwrapSlotsType<S>
emit: EmitFn<E>
expose: <Exposed extends Record<string, any> = Record<string, any>>(
exposed?: Exposed,
) => void
expose: <Exposed extends EX = EX>(exposed?: Exposed) => void
}
: never

Expand Down