feat(types): add emits and slots type to `FunctionalComponent` (#8644)
This commit is contained in:
parent
bfb856565d
commit
927ab17cfc
|
@ -8,14 +8,22 @@ import {
|
||||||
FunctionalComponent,
|
FunctionalComponent,
|
||||||
ComponentPublicInstance,
|
ComponentPublicInstance,
|
||||||
toRefs,
|
toRefs,
|
||||||
SetupContext
|
SetupContext,
|
||||||
|
EmitsOptions
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { describe, expectAssignable, expectType, IsAny } from './utils'
|
import { describe, expectAssignable, expectType, IsAny } from './utils'
|
||||||
|
|
||||||
declare function extractComponentOptions<Props, RawBindings>(
|
declare function extractComponentOptions<
|
||||||
obj: Component<Props, RawBindings>
|
Props,
|
||||||
|
RawBindings,
|
||||||
|
Emits extends EmitsOptions | Record<string, any[]>,
|
||||||
|
Slots extends Record<string, any>
|
||||||
|
>(
|
||||||
|
obj: Component<Props, RawBindings, any, any, any, Emits, Slots>
|
||||||
): {
|
): {
|
||||||
props: Props
|
props: Props
|
||||||
|
emits: Emits
|
||||||
|
slots: Slots
|
||||||
rawBindings: RawBindings
|
rawBindings: RawBindings
|
||||||
setup: ShallowUnwrapRef<RawBindings>
|
setup: ShallowUnwrapRef<RawBindings>
|
||||||
}
|
}
|
||||||
|
@ -455,11 +463,27 @@ describe('functional', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('typed', () => {
|
describe('typed', () => {
|
||||||
const MyComponent: FunctionalComponent<{ foo: number }> = (_, _2) => {}
|
type Props = { foo: number }
|
||||||
|
type Emits = { change: [value: string]; inc: [value: number] }
|
||||||
|
type Slots = { default: (scope: { foo: string }) => any }
|
||||||
|
|
||||||
const { props } = extractComponentOptions(MyComponent)
|
const MyComponent: FunctionalComponent<Props, Emits, Slots> = (
|
||||||
|
props,
|
||||||
|
{ emit, slots }
|
||||||
|
) => {
|
||||||
|
expectType<Props>(props)
|
||||||
|
expectType<{
|
||||||
|
(event: 'change', value: string): void
|
||||||
|
(event: 'inc', value: number): void
|
||||||
|
}>(emit)
|
||||||
|
expectType<Slots>(slots)
|
||||||
|
}
|
||||||
|
|
||||||
expectType<number>(props.foo)
|
const { props, emits, slots } = extractComponentOptions(MyComponent)
|
||||||
|
|
||||||
|
expectType<Props>(props)
|
||||||
|
expectType<Emits>(emits)
|
||||||
|
expectType<Slots>(slots)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -481,4 +505,18 @@ describe('SetupContext', () => {
|
||||||
|
|
||||||
expectAssignable<SetupContext<{ b: () => true }>>(wider)
|
expectAssignable<SetupContext<{ b: () => true }>>(wider)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('short emits', () => {
|
||||||
|
const {
|
||||||
|
emit
|
||||||
|
}: SetupContext<{
|
||||||
|
a: [val: string]
|
||||||
|
b: [val: number]
|
||||||
|
}> = {} as any
|
||||||
|
|
||||||
|
expectType<{
|
||||||
|
(event: 'a', val: string): void
|
||||||
|
(event: 'b', val: number): void
|
||||||
|
}>(emit)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -51,7 +51,8 @@ import {
|
||||||
EmitFn,
|
EmitFn,
|
||||||
emit,
|
emit,
|
||||||
normalizeEmitsOptions,
|
normalizeEmitsOptions,
|
||||||
EmitsToProps
|
EmitsToProps,
|
||||||
|
ShortEmitsToObject
|
||||||
} from './componentEmits'
|
} from './componentEmits'
|
||||||
import {
|
import {
|
||||||
EMPTY_OBJ,
|
EMPTY_OBJ,
|
||||||
|
@ -160,16 +161,17 @@ export interface ComponentInternalOptions {
|
||||||
|
|
||||||
export interface FunctionalComponent<
|
export interface FunctionalComponent<
|
||||||
P = {},
|
P = {},
|
||||||
E extends EmitsOptions = {},
|
E extends EmitsOptions | Record<string, any[]> = {},
|
||||||
S extends Record<string, any> = any
|
S extends Record<string, any> = any,
|
||||||
|
EE extends EmitsOptions = ShortEmitsToObject<E>
|
||||||
> extends ComponentInternalOptions {
|
> extends ComponentInternalOptions {
|
||||||
// use of any here is intentional so it can be a valid JSX Element constructor
|
// use of any here is intentional so it can be a valid JSX Element constructor
|
||||||
(
|
(
|
||||||
props: P & EmitsToProps<E>,
|
props: P & EmitsToProps<EE>,
|
||||||
ctx: Omit<SetupContext<E, IfAny<S, {}, SlotsType<S>>>, 'expose'>
|
ctx: Omit<SetupContext<EE, IfAny<S, {}, SlotsType<S>>>, 'expose'>
|
||||||
): any
|
): any
|
||||||
props?: ComponentPropsOptions<P>
|
props?: ComponentPropsOptions<P>
|
||||||
emits?: E | (keyof E)[]
|
emits?: EE | (keyof EE)[]
|
||||||
slots?: IfAny<S, Slots, SlotsType<S>>
|
slots?: IfAny<S, Slots, SlotsType<S>>
|
||||||
inheritAttrs?: boolean
|
inheritAttrs?: boolean
|
||||||
displayName?: string
|
displayName?: string
|
||||||
|
@ -192,10 +194,12 @@ export type ConcreteComponent<
|
||||||
RawBindings = any,
|
RawBindings = any,
|
||||||
D = any,
|
D = any,
|
||||||
C extends ComputedOptions = ComputedOptions,
|
C extends ComputedOptions = ComputedOptions,
|
||||||
M extends MethodOptions = MethodOptions
|
M extends MethodOptions = MethodOptions,
|
||||||
|
E extends EmitsOptions | Record<string, any[]> = {},
|
||||||
|
S extends Record<string, any> = any
|
||||||
> =
|
> =
|
||||||
| ComponentOptions<Props, RawBindings, D, C, M>
|
| ComponentOptions<Props, RawBindings, D, C, M>
|
||||||
| FunctionalComponent<Props, any>
|
| FunctionalComponent<Props, E, S>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A type used in public APIs where a component type is expected.
|
* A type used in public APIs where a component type is expected.
|
||||||
|
@ -206,9 +210,11 @@ export type Component<
|
||||||
RawBindings = any,
|
RawBindings = any,
|
||||||
D = any,
|
D = any,
|
||||||
C extends ComputedOptions = ComputedOptions,
|
C extends ComputedOptions = ComputedOptions,
|
||||||
M extends MethodOptions = MethodOptions
|
M extends MethodOptions = MethodOptions,
|
||||||
|
E extends EmitsOptions | Record<string, any[]> = {},
|
||||||
|
S extends Record<string, any> = any
|
||||||
> =
|
> =
|
||||||
| ConcreteComponent<Props, RawBindings, D, C, M>
|
| ConcreteComponent<Props, RawBindings, D, C, M, E, S>
|
||||||
| ComponentPublicInstanceConstructor<Props>
|
| ComponentPublicInstanceConstructor<Props>
|
||||||
|
|
||||||
export type { ComponentOptions }
|
export type { ComponentOptions }
|
||||||
|
|
|
@ -55,6 +55,12 @@ export type EmitsToProps<T extends EmitsOptions> = T extends string[]
|
||||||
}
|
}
|
||||||
: {}
|
: {}
|
||||||
|
|
||||||
|
export type ShortEmitsToObject<E> = E extends Record<string, any[]>
|
||||||
|
? {
|
||||||
|
[K in keyof E]: (...args: E[K]) => any
|
||||||
|
}
|
||||||
|
: E
|
||||||
|
|
||||||
export type EmitFn<
|
export type EmitFn<
|
||||||
Options = ObjectEmitsOptions,
|
Options = ObjectEmitsOptions,
|
||||||
Event extends keyof Options = keyof Options
|
Event extends keyof Options = keyof Options
|
||||||
|
@ -66,7 +72,9 @@ export type EmitFn<
|
||||||
{
|
{
|
||||||
[key in Event]: Options[key] extends (...args: infer Args) => any
|
[key in Event]: Options[key] extends (...args: infer Args) => any
|
||||||
? (event: key, ...args: Args) => void
|
? (event: key, ...args: Args) => void
|
||||||
: (event: key, ...args: any[]) => void
|
: Options[key] extends any[]
|
||||||
|
? (event: key, ...args: Options[key]) => void
|
||||||
|
: (event: key, ...args: any[]) => void
|
||||||
}[Event]
|
}[Event]
|
||||||
>
|
>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue