Skip to content

Commit 1c64108

Browse files
authored
fix(type): improve defineComponent type for option apis (#406)
* fix(type): improve defineComponent type for option apis * test: add dts tests for defineComponent fix
1 parent 048b6d3 commit 1c64108

File tree

9 files changed

+854
-171
lines changed

9 files changed

+854
-171
lines changed

src/component/common.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export type Data = { [key: string]: unknown }

src/component/component.ts

Lines changed: 0 additions & 161 deletions
This file was deleted.

src/component/componentOptions.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { Data } from './common'
2+
import { ComponentPropsOptions, ExtractPropTypes } from './componentProps'
3+
import { VNode } from 'vue'
4+
import { ComponentInstance, ComponentRenderProxy } from './componentProxy'
5+
6+
import { ComponentOptions as Vue2ComponentOptions } from 'vue'
7+
8+
export interface SetupContext {
9+
readonly attrs: Record<string, string>
10+
readonly slots: { [key: string]: (...args: any[]) => VNode[] }
11+
readonly parent: ComponentInstance | null
12+
readonly root: ComponentInstance
13+
readonly listeners: { [key: string]: Function }
14+
15+
emit(event: string, ...args: any[]): void
16+
}
17+
18+
export type ComputedGetter<T> = (ctx?: any) => T
19+
export type ComputedSetter<T> = (v: T) => void
20+
21+
export interface WritableComputedOptions<T> {
22+
get: ComputedGetter<T>
23+
set: ComputedSetter<T>
24+
}
25+
26+
export type ComputedOptions = Record<
27+
string,
28+
ComputedGetter<any> | WritableComputedOptions<any>
29+
>
30+
31+
export interface MethodOptions {
32+
[key: string]: Function
33+
}
34+
35+
export type SetupFunction<Props, RawBindings> = (
36+
this: void,
37+
props: Props,
38+
ctx: SetupContext
39+
) => RawBindings | (() => VNode | null)
40+
41+
interface ComponentOptionsBase<
42+
Props,
43+
D = Data,
44+
C extends ComputedOptions = {},
45+
M extends MethodOptions = {}
46+
>
47+
extends Omit<
48+
Vue2ComponentOptions<Vue, D, M, C, Props>,
49+
'data' | 'computed' | 'method' | 'setup' | 'props'
50+
> {
51+
data?: (this: Props, vm: Props) => D
52+
computed?: C
53+
methods?: M
54+
}
55+
56+
export type ExtractComputedReturns<T extends any> = {
57+
[key in keyof T]: T[key] extends { get: (...args: any[]) => infer TReturn }
58+
? TReturn
59+
: T[key] extends (...args: any[]) => infer TReturn
60+
? TReturn
61+
: never
62+
}
63+
64+
export type ComponentOptionsWithProps<
65+
PropsOptions = ComponentPropsOptions,
66+
RawBindings = Data,
67+
D = Data,
68+
C extends ComputedOptions = {},
69+
M extends MethodOptions = {},
70+
Props = ExtractPropTypes<PropsOptions>
71+
> = ComponentOptionsBase<Props, D, C, M> & {
72+
props?: PropsOptions
73+
setup?: SetupFunction<Props, RawBindings>
74+
} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>>
75+
76+
export type ComponentOptionsWithArrayProps<
77+
PropNames extends string = string,
78+
RawBindings = Data,
79+
D = Data,
80+
C extends ComputedOptions = {},
81+
M extends MethodOptions = {},
82+
Props = Readonly<{ [key in PropNames]?: any }>
83+
> = ComponentOptionsBase<Props, D, C, M> & {
84+
props?: PropNames[]
85+
setup?: SetupFunction<Props, RawBindings>
86+
} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>>
87+
88+
export type ComponentOptionsWithoutProps<
89+
Props = unknown,
90+
RawBindings = Data,
91+
D = Data,
92+
C extends ComputedOptions = {},
93+
M extends MethodOptions = {}
94+
> = ComponentOptionsBase<Props, D, C, M> & {
95+
props?: undefined
96+
setup?: SetupFunction<Props, RawBindings>
97+
} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>>
98+
99+
export type WithLegacyAPI<T, D, C, M, Props> = T &
100+
Omit<Vue2ComponentOptions<Vue, D, M, C, Props>, keyof T>

src/component/componentProps.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Data } from './component'
1+
import { Data } from './common'
22

33
export type ComponentPropsOptions<P = Data> =
44
| ComponentObjectPropsOptions<P>

src/component/componentProxy.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { ExtractPropTypes } from './componentProps'
2+
import { UnwrapRef } from '..'
3+
import { Data } from './common'
4+
5+
import Vue, {
6+
VueConstructor,
7+
ComponentOptions as Vue2ComponentOptions,
8+
} from 'vue'
9+
import {
10+
ComputedOptions,
11+
MethodOptions,
12+
ExtractComputedReturns,
13+
} from './componentOptions'
14+
15+
export type ComponentInstance = InstanceType<VueConstructor>
16+
17+
// public properties exposed on the proxy, which is used as the render context
18+
// in templates (as `this` in the render option)
19+
export type ComponentRenderProxy<
20+
P = {}, // props type extracted from props option
21+
B = {}, // raw bindings returned from setup()
22+
D = {}, // return from data()
23+
C extends ComputedOptions = {},
24+
M extends MethodOptions = {},
25+
PublicProps = P
26+
> = {
27+
$data: D
28+
$props: Readonly<P & PublicProps>
29+
$attrs: Data
30+
$refs: Data
31+
$slots: Data
32+
$root: ComponentInstance | null
33+
$parent: ComponentInstance | null
34+
$emit: (event: string, ...args: unknown[]) => void
35+
} & Readonly<P> &
36+
UnwrapRef<B> &
37+
D &
38+
M &
39+
ExtractComputedReturns<C> &
40+
Vue
41+
42+
// for Vetur and TSX support
43+
type VueConstructorProxy<PropsOptions, RawBindings> = VueConstructor & {
44+
new (...args: any[]): ComponentRenderProxy<
45+
ExtractPropTypes<PropsOptions>,
46+
UnwrapRef<RawBindings>,
47+
ExtractPropTypes<PropsOptions, false>
48+
>
49+
}
50+
51+
type DefaultData<V> = object | ((this: V) => object)
52+
type DefaultMethods<V> = { [key: string]: (this: V, ...args: any[]) => any }
53+
type DefaultComputed = { [key: string]: any }
54+
55+
export type VueProxy<
56+
PropsOptions,
57+
RawBindings,
58+
Data = DefaultData<Vue>,
59+
Computed = DefaultComputed,
60+
Methods = DefaultMethods<Vue>
61+
> = Vue2ComponentOptions<
62+
Vue,
63+
UnwrapRef<RawBindings> & Data,
64+
Methods,
65+
Computed,
66+
PropsOptions,
67+
ExtractPropTypes<PropsOptions, false>
68+
> &
69+
VueConstructorProxy<PropsOptions, RawBindings>

0 commit comments

Comments
 (0)