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,
|
||||
ComponentPublicInstance,
|
||||
toRefs,
|
||||
SetupContext
|
||||
SetupContext,
|
||||
EmitsOptions
|
||||
} from 'vue'
|
||||
import { describe, expectAssignable, expectType, IsAny } from './utils'
|
||||
|
||||
declare function extractComponentOptions<Props, RawBindings>(
|
||||
obj: Component<Props, RawBindings>
|
||||
declare function extractComponentOptions<
|
||||
Props,
|
||||
RawBindings,
|
||||
Emits extends EmitsOptions | Record<string, any[]>,
|
||||
Slots extends Record<string, any>
|
||||
>(
|
||||
obj: Component<Props, RawBindings, any, any, any, Emits, Slots>
|
||||
): {
|
||||
props: Props
|
||||
emits: Emits
|
||||
slots: Slots
|
||||
rawBindings: RawBindings
|
||||
setup: ShallowUnwrapRef<RawBindings>
|
||||
}
|
||||
|
@ -455,11 +463,27 @@ describe('functional', () => {
|
|||
})
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
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,
|
||||
emit,
|
||||
normalizeEmitsOptions,
|
||||
EmitsToProps
|
||||
EmitsToProps,
|
||||
ShortEmitsToObject
|
||||
} from './componentEmits'
|
||||
import {
|
||||
EMPTY_OBJ,
|
||||
|
@ -160,16 +161,17 @@ export interface ComponentInternalOptions {
|
|||
|
||||
export interface FunctionalComponent<
|
||||
P = {},
|
||||
E extends EmitsOptions = {},
|
||||
S extends Record<string, any> = any
|
||||
E extends EmitsOptions | Record<string, any[]> = {},
|
||||
S extends Record<string, any> = any,
|
||||
EE extends EmitsOptions = ShortEmitsToObject<E>
|
||||
> extends ComponentInternalOptions {
|
||||
// use of any here is intentional so it can be a valid JSX Element constructor
|
||||
(
|
||||
props: P & EmitsToProps<E>,
|
||||
ctx: Omit<SetupContext<E, IfAny<S, {}, SlotsType<S>>>, 'expose'>
|
||||
props: P & EmitsToProps<EE>,
|
||||
ctx: Omit<SetupContext<EE, IfAny<S, {}, SlotsType<S>>>, 'expose'>
|
||||
): any
|
||||
props?: ComponentPropsOptions<P>
|
||||
emits?: E | (keyof E)[]
|
||||
emits?: EE | (keyof EE)[]
|
||||
slots?: IfAny<S, Slots, SlotsType<S>>
|
||||
inheritAttrs?: boolean
|
||||
displayName?: string
|
||||
|
@ -192,10 +194,12 @@ export type ConcreteComponent<
|
|||
RawBindings = any,
|
||||
D = any,
|
||||
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>
|
||||
| FunctionalComponent<Props, any>
|
||||
| FunctionalComponent<Props, E, S>
|
||||
|
||||
/**
|
||||
* A type used in public APIs where a component type is expected.
|
||||
|
@ -206,9 +210,11 @@ export type Component<
|
|||
RawBindings = any,
|
||||
D = any,
|
||||
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>
|
||||
|
||||
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<
|
||||
Options = ObjectEmitsOptions,
|
||||
Event extends keyof Options = keyof Options
|
||||
|
@ -66,7 +72,9 @@ export type EmitFn<
|
|||
{
|
||||
[key in Event]: Options[key] extends (...args: infer Args) => any
|
||||
? (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]
|
||||
>
|
||||
|
||||
|
|
Loading…
Reference in New Issue