Skip to content

Commit 206f8a7

Browse files
committed
wip: defineComponent
1 parent 09beea9 commit 206f8a7

16 files changed

+722
-59
lines changed

src/types/component.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type VNode from 'core/vdom/vnode'
22
import type Watcher from 'core/observer/watcher'
3-
import { ComponentOptions, SetupContext } from './options'
3+
import { ComponentOptions } from './options'
4+
import { SetupContext } from 'v3/apiSetup'
45
import { ScopedSlotsData, VNodeChildren, VNodeData } from './vnode'
56
import { GlobalAPI } from './global-api'
67
import { EffectScope } from 'v3/reactivity/effectScope'

src/types/options.ts

+2-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import VNode from 'core/vdom/vnode'
2-
import { DebuggerEvent } from 'v3'
2+
import { DebuggerEvent } from 'v3/debug'
3+
import { SetupContext } from 'v3/apiSetup'
34
import { Component } from './component'
45

56
export type InternalComponentOptions = {
@@ -12,15 +13,6 @@ export type InternalComponentOptions = {
1213

1314
type InjectKey = string | Symbol
1415

15-
/**
16-
* @internal
17-
*/
18-
export interface SetupContext {
19-
attrs: Record<string, any>
20-
slots: Record<string, () => VNode[]>
21-
emit: (event: string, ...args: any[]) => any
22-
}
23-
2416
/**
2517
* @internal
2618
*/

src/v3/apiSetup.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
import { Component } from 'types/component'
2-
import type { SetupContext } from 'types/options'
32
import { def, invokeWithErrorHandling, isReserved, warn } from '../core/util'
43
import VNode from '../core/vdom/vnode'
54
import { bind, emptyObject, isFunction, isObject } from '../shared/util'
65
import { currentInstance, setCurrentInstance } from './currentInstance'
76
import { isRef } from './reactivity/ref'
87

8+
/**
9+
* @internal
10+
*/
11+
export interface SetupContext {
12+
attrs: Record<string, any>
13+
slots: Record<string, () => VNode[]>
14+
emit: (event: string, ...args: any[]) => any
15+
}
16+
917
export function initSetup(vm: Component) {
1018
const options = vm.$options
1119
const setup = options.setup

src/v3/index.ts

+7
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,11 @@ export { useSlots, useAttrs } from './apiSetup'
7474
export { nextTick } from 'core/util/next-tick'
7575
export { set, del } from 'core/observer'
7676

77+
/**
78+
* @internal type is manually declared in <root>/types/v3-define-component.d.ts
79+
*/
80+
export function defineComponent(options: any) {
81+
return options
82+
}
83+
7784
export * from './apiLifecycle'

types/common.d.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export type Data = { [key: string]: unknown }
2+
3+
export type UnionToIntersection<U> = (
4+
U extends any ? (k: U) => void : never
5+
) extends (k: infer I) => void
6+
? I
7+
: never
8+
9+
// Conditional returns can enforce identical types.
10+
// See here: https://github.com/Microsoft/TypeScript/issues/27024#issuecomment-421529650
11+
// prettier-ignore
12+
type Equal<Left, Right> =
13+
(<U>() => U extends Left ? 1 : 0) extends (<U>() => U extends Right ? 1 : 0) ? true : false;
14+
15+
export type HasDefined<T> = Equal<T, unknown> extends true ? false : true

types/index.d.ts

+34-3
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ export {
1111
ComponentOptions,
1212
FunctionalComponentOptions,
1313
RenderContext,
14-
PropType,
15-
PropOptions,
14+
// PropType,
15+
// PropOptions,
1616
ComputedOptions,
1717
WatchHandler,
1818
WatchOptions,
@@ -32,5 +32,36 @@ export {
3232
VNodeDirective
3333
} from './vnode'
3434

35-
export * from './v3'
35+
export * from './v3-manual-apis'
3636
export * from './v3-generated'
37+
38+
export { Data } from './common'
39+
export { SetupContext } from './v3-setup-context'
40+
export { defineComponent } from './v3-define-component'
41+
// export { defineAsyncComponent } from './defineAsyncComponent'
42+
export {
43+
SetupFunction,
44+
// v2 already has option with same name and it's for a single computed
45+
ComputedOptions as ComponentComputedOptions,
46+
MethodOptions as ComponentMethodOptions,
47+
ComponentPropsOptions
48+
} from './v3-component-options'
49+
export {
50+
ComponentInstance,
51+
ComponentPublicInstance,
52+
ComponentRenderProxy
53+
} from './v3-component-proxy'
54+
export {
55+
PropType,
56+
PropOptions,
57+
ExtractPropTypes,
58+
ExtractDefaultPropTypes
59+
} from './v3-component-props'
60+
export {
61+
DirectiveModifiers,
62+
DirectiveBinding,
63+
DirectiveHook,
64+
ObjectDirective,
65+
FunctionDirective,
66+
Directive
67+
} from './v3-directive'

types/options.d.ts

+3-35
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Vue, CreateElement, CombinedVueInstance } from './vue'
22
import { VNode, VNodeData, VNodeDirective, NormalizedScopedSlot } from './vnode'
3-
import { SetupContext } from './v3'
3+
import { SetupContext } from './v3-setup-context'
4+
import { DebuggerEvent } from './v3-generated'
45

56
type Constructor = {
67
new (...args: any[]): any
@@ -249,22 +250,10 @@ export interface RenderContext<Props = DefaultProps> {
249250
injections: any
250251
}
251252

252-
export type Prop<T> =
253-
| { (): T }
254-
| { new (...args: never[]): T & object }
255-
| { new (...args: string[]): Function }
256-
257-
export type PropType<T> = Prop<T> | Prop<T>[]
253+
import { PropOptions, PropType } from './v3-component-props'
258254

259255
export type PropValidator<T> = PropOptions<T> | PropType<T>
260256

261-
export interface PropOptions<T = any> {
262-
type?: PropType<T>
263-
required?: boolean
264-
default?: T | null | undefined | (() => T | null | undefined)
265-
validator?(value: T): boolean
266-
}
267-
268257
export type RecordPropsDefinition<T> = {
269258
[K in keyof T]: PropValidator<T[K]>
270259
}
@@ -316,24 +305,3 @@ export type InjectOptions =
316305
[key: string]: InjectKey | { from?: InjectKey; default?: any }
317306
}
318307
| string[]
319-
320-
export type DebuggerEvent = {
321-
target: object
322-
type: TrackOpTypes | TriggerOpTypes
323-
key?: any
324-
newValue?: any
325-
oldValue?: any
326-
oldTarget?: Map<any, any> | Set<any>
327-
}
328-
329-
export const enum TrackOpTypes {
330-
GET = 'get',
331-
TOUCH = 'touch'
332-
}
333-
334-
export const enum TriggerOpTypes {
335-
SET = 'set',
336-
ADD = 'add',
337-
DELETE = 'delete',
338-
ARRAY_MUTATION = 'array mutation'
339-
}

types/test/v3/setup-test.ts

+49-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Vue from '../../index'
1+
import Vue, { defineComponent } from '../../index'
22

33
// object props
44
Vue.extend({
@@ -30,3 +30,51 @@ Vue.extend({
3030
ctx.slots.default && ctx.slots.default()
3131
}
3232
})
33+
34+
// object props
35+
defineComponent({
36+
props: {
37+
foo: String,
38+
bar: Number
39+
},
40+
setup(props) {
41+
// @ts-expect-error
42+
props.foo.slice(1, 2)
43+
44+
props.foo?.slice(1, 2)
45+
46+
// @ts-expect-error
47+
props.bar + 123
48+
49+
props.bar?.toFixed(2)
50+
}
51+
})
52+
53+
// array props
54+
defineComponent({
55+
props: ['foo', 'bar'],
56+
setup(props) {
57+
props.foo
58+
props.bar
59+
}
60+
})
61+
62+
// context
63+
defineComponent({
64+
emits: ['foo'],
65+
setup(_props, ctx) {
66+
if (ctx.attrs.id) {
67+
}
68+
ctx.emit('foo')
69+
// @ts-expect-error
70+
ctx.emit('ok')
71+
ctx.slots.default && ctx.slots.default()
72+
},
73+
methods: {
74+
foo() {
75+
this.$emit('foo')
76+
// @ts-expect-error
77+
this.$emit('bar')
78+
}
79+
}
80+
})

types/tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@
1212
"vue": ["../index.d.ts"]
1313
}
1414
},
15-
"include": ["./*.d.ts", "*.ts"],
15+
"include": ["."],
1616
"compileOnSave": false
1717
}

types/v3-component-options.d.ts

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import { Vue } from './vue'
2+
import { VNode } from './vnode'
3+
import { ComponentOptions as Vue2ComponentOptions } from './options'
4+
import { EmitsOptions, SetupContext } from './v3-setup-context'
5+
import { Data } from './common'
6+
import { ComponentPropsOptions, ExtractPropTypes } from './v3-component-props'
7+
import { ComponentRenderProxy } from './v3-component-proxy'
8+
export { ComponentPropsOptions } from './v3-component-props'
9+
10+
export type ComputedGetter<T> = (ctx?: any) => T
11+
export type ComputedSetter<T> = (v: T) => void
12+
13+
export interface WritableComputedOptions<T> {
14+
get: ComputedGetter<T>
15+
set: ComputedSetter<T>
16+
}
17+
18+
export type ComputedOptions = Record<
19+
string,
20+
ComputedGetter<any> | WritableComputedOptions<any>
21+
>
22+
23+
export interface MethodOptions {
24+
[key: string]: Function
25+
}
26+
27+
export type SetupFunction<
28+
Props,
29+
RawBindings = {},
30+
Emits extends EmitsOptions = {}
31+
> = (
32+
this: void,
33+
props: Readonly<Props>,
34+
ctx: SetupContext<Emits>
35+
) => RawBindings | (() => VNode | null) | void
36+
37+
interface ComponentOptionsBase<
38+
Props,
39+
D = Data,
40+
C extends ComputedOptions = {},
41+
M extends MethodOptions = {}
42+
> extends Omit<
43+
Vue2ComponentOptions<Vue, D, M, C, Props>,
44+
'data' | 'computed' | 'method' | 'setup' | 'props'
45+
> {
46+
// allow any custom options
47+
[key: string]: any
48+
49+
// rewrite options api types
50+
data?: (this: Props & Vue, vm: Props) => D
51+
computed?: C
52+
methods?: M
53+
}
54+
55+
export type ExtractComputedReturns<T extends any> = {
56+
[key in keyof T]: T[key] extends { get: (...args: any[]) => infer TReturn }
57+
? TReturn
58+
: T[key] extends (...args: any[]) => infer TReturn
59+
? TReturn
60+
: never
61+
}
62+
63+
export type ComponentOptionsWithProps<
64+
PropsOptions = ComponentPropsOptions,
65+
RawBindings = Data,
66+
D = Data,
67+
C extends ComputedOptions = {},
68+
M extends MethodOptions = {},
69+
Mixin = {},
70+
Extends = {},
71+
Emits extends EmitsOptions = {},
72+
EmitsNames extends string = string,
73+
Props = ExtractPropTypes<PropsOptions>
74+
> = ComponentOptionsBase<Props, D, C, M> & {
75+
props?: PropsOptions
76+
emits?: (Emits | EmitsNames[]) & ThisType<void>
77+
setup?: SetupFunction<Props, RawBindings, Emits>
78+
} & ThisType<
79+
ComponentRenderProxy<Props, RawBindings, D, C, M, Mixin, Extends, Emits>
80+
>
81+
82+
export type ComponentOptionsWithArrayProps<
83+
PropNames extends string = string,
84+
RawBindings = Data,
85+
D = Data,
86+
C extends ComputedOptions = {},
87+
M extends MethodOptions = {},
88+
Mixin = {},
89+
Extends = {},
90+
Emits extends EmitsOptions = {},
91+
EmitsNames extends string = string,
92+
Props = Readonly<{ [key in PropNames]?: any }>
93+
> = ComponentOptionsBase<Props, D, C, M> & {
94+
props?: PropNames[]
95+
emits?: (Emits | EmitsNames[]) & ThisType<void>
96+
setup?: SetupFunction<Props, RawBindings, Emits>
97+
} & ThisType<
98+
ComponentRenderProxy<Props, RawBindings, D, C, M, Mixin, Extends, Emits>
99+
>
100+
101+
export type ComponentOptionsWithoutProps<
102+
Props = {},
103+
RawBindings = Data,
104+
D = Data,
105+
C extends ComputedOptions = {},
106+
M extends MethodOptions = {},
107+
Mixin = {},
108+
Extends = {},
109+
Emits extends EmitsOptions = {},
110+
EmitsNames extends string = string
111+
> = ComponentOptionsBase<Props, D, C, M> & {
112+
props?: undefined
113+
emits?: (Emits | EmitsNames[]) & ThisType<void>
114+
setup?: SetupFunction<Props, RawBindings, Emits>
115+
} & ThisType<
116+
ComponentRenderProxy<Props, RawBindings, D, C, M, Mixin, Extends, Emits>
117+
>
118+
119+
export type WithLegacyAPI<T, D, C, M, Props> = T &
120+
Omit<Vue2ComponentOptions<Vue, D, M, C, Props>, keyof T>

0 commit comments

Comments
 (0)