Skip to content

Commit 8cd5b9c

Browse files
Got 'new Vue(...)', 'Vue.extend(...)', and 'Vue.component(...)' working.
1 parent 385a744 commit 8cd5b9c

File tree

3 files changed

+103
-30
lines changed

3 files changed

+103
-30
lines changed

Diff for: types/options.d.ts

+65-14
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,20 @@ type Constructor = {
55
new (...args: any[]): any;
66
}
77

8-
export type Component<Data = any, Methods = any, Computed = any> = typeof Vue | ComponentOptions<Data, Methods, Computed> | FunctionalComponentOptions;
9-
export type AsyncComponent<Data = any, Methods = any, Computed = any> = (
10-
resolve: (component: Component<Data, Methods, Computed>) => void,
8+
export type Component<Data, Methods, Computed, PropNames extends string = never> =
9+
typeof Vue |
10+
FunctionalOrStandardComponentOptions<Data, Methods, Computed, PropNames>;
11+
12+
export type AsyncComponent<Data, Methods, Computed, PropNames extends string> = (
13+
resolve: (component: Component<Data, Methods, Computed, PropNames>) => void,
14+
reject: (reason?: any) => void
15+
) => Promise<Component<Data, Methods, Computed, PropNames>> | Component<Data, Methods, Computed, PropNames> | void;
16+
17+
export type MyAsyncComponent<Data, Methods, Computed, PropNames extends string> = (
18+
resolve: (component: Component<Data, Methods, Computed, PropNames>) => void,
1119
reject: (reason?: any) => void
12-
) => Promise<Component<Data, Methods, Computed>> | Component<Data, Methods, Computed> | void;
20+
) => Promise<Component<Data, Methods, Computed, PropNames>> | Component<Data, Methods, Computed, PropNames> | void;
21+
1322

1423
/**
1524
* When the `Computed` type parameter on `ComponentOptions` is inferred,
@@ -21,9 +30,49 @@ export type Accessors<T> = {
2130
[K in keyof T]: (() => T[K]) | ComputedOptions<T[K]>
2231
}
2332

24-
export interface ComponentOptions<Data, Methods, Computed> {
33+
/**
34+
* A general type that
35+
*
36+
* - Describes (non-functional) component options in Vue.
37+
* - Gives the appropriate type to `this` in each method in objects of this type.
38+
*
39+
* Use this only if the following two types become too cumbersome.
40+
*/
41+
export type ThisTypedComponentOptions<Data, Methods, Computed, PropNames extends string = never, Instance extends AnyVue = Vue<Data, Methods, Computed, Record<PropNames, any>>> =
42+
object &
43+
ComponentOptions<Data, Methods, Computed, PropNames[] | Record<PropNames, PropOptions>> &
44+
ThisType<Data & Methods & Computed & Record<PropNames, any> & Instance>;
45+
46+
/**
47+
* A specialized version of `ThisTypedComponentOptions`.
48+
* This type should be used when a parameter type only contains an array of strings for its `props` value.
49+
*/
50+
export type ThisTypedComponentOptionsWithArrayProps<Data, Methods, Computed, PropNames extends string, Instance extends AnyVue = Vue<Data, Methods, Computed, PropNames>> =
51+
object &
52+
ComponentOptions<Data, Methods, Computed, PropNames[]> &
53+
ThisType<Data & Methods & Computed & Record<PropNames, any> & Instance>;
54+
55+
/**
56+
* A specialized version of `ThisTypedComponentOptions`.
57+
* This type should be used when a parameter type only contains an object mapped to `PropOptions` for its `props` value.
58+
*/
59+
export type ThisTypedComponentOptionsWithRecordProps<Data, Methods, Computed, Props, Instance extends AnyVue = Vue<Data, Methods, Computed, Props>> =
60+
object &
61+
ComponentOptions<Data, Methods, Computed, Props> &
62+
ThisType<Data & Methods & Computed & Record<keyof Props, any> & Instance>;
63+
64+
/**
65+
* A helper type that describes options for either functional or non-functional components.
66+
* Useful for `Vue.extend` and `Vue.component`.
67+
*/
68+
export type FunctionalOrStandardComponentOptions<Data, Methods, Computed, PropNames extends string = never> =
69+
ThisTypedComponentOptions<Data, Methods, Computed, PropNames> |
70+
FunctionalComponentOptions<PropNames[] | Record<PropNames, PropValidator>, Record<PropNames, any>>;
71+
72+
73+
export interface ComponentOptions<Data, Methods, Computed, Props> {
2574
data?: Data | (() => Data);
26-
props?: string[] | { [key: string]: PropOptions | Constructor | Constructor[] };
75+
props?: Props;
2776
propsData?: Object;
2877
computed?: Accessors<Computed>;
2978
methods?: Methods;
@@ -47,7 +96,7 @@ export interface ComponentOptions<Data, Methods, Computed> {
4796
deactivated?(): void;
4897

4998
directives?: { [key: string]: DirectiveOptions | DirectiveFunction };
50-
components?: { [key: string]: Component | AsyncComponent };
99+
components?: { [key: string]: Component<any, any, any, never> | AsyncComponent<any, any, any, never> };
51100
transitions?: { [key: string]: Object };
52101
filters?: { [key: string]: Function };
53102

@@ -60,32 +109,34 @@ export interface ComponentOptions<Data, Methods, Computed> {
60109
};
61110

62111
parent?: AnyVue;
63-
mixins?: (ComponentOptions<any, any, any> | typeof Vue)[];
112+
mixins?: (ComponentOptions<any, any, any, any> | typeof Vue)[];
64113
name?: string;
65114
// TODO: support properly inferred 'extends'
66-
extends?: ComponentOptions<any, any, any> | typeof Vue;
115+
extends?: ComponentOptions<any, any, any, any> | typeof Vue;
67116
delimiters?: [string, string];
68117
}
69118

70-
export interface FunctionalComponentOptions {
119+
export interface FunctionalComponentOptions<Props, ContextProps> {
71120
props?: string[] | { [key: string]: PropOptions | Constructor | Constructor[] };
72121
functional: boolean;
73-
render(this: never, createElement: CreateElement, context: RenderContext): VNode;
122+
render(this: never, createElement: CreateElement, context: RenderContext<ContextProps>): VNode;
74123
name?: string;
75124
}
76125

77-
export interface RenderContext {
78-
props: any;
126+
export interface RenderContext<Props> {
127+
props: Props;
79128
children: VNode[];
80129
slots(): any;
81130
data: VNodeData;
82131
parent: AnyVue;
83132
}
84133

134+
export type PropValidator = PropOptions | Constructor | Constructor[];
135+
85136
export interface PropOptions {
86137
type?: Constructor | Constructor[] | null;
87138
required?: boolean;
88-
default?: any;
139+
default?: string | number | boolean | null | undefined | (() => object);
89140
validator?(value: any): boolean;
90141
}
91142

Diff for: types/vnode.d.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Vue } from "./vue";
1+
import { Vue, AnyVue } from "./vue";
22

33
export type ScopedSlot = (props: any) => VNodeChildrenArrayContents | string;
44

@@ -14,10 +14,10 @@ export interface VNode {
1414
text?: string;
1515
elm?: Node;
1616
ns?: string;
17-
context?: Vue;
17+
context?: AnyVue;
1818
key?: string | number;
1919
componentOptions?: VNodeComponentOptions;
20-
componentInstance?: Vue;
20+
componentInstance?: AnyVue;
2121
parent?: VNode;
2222
raw?: boolean;
2323
isStatic?: boolean;

Diff for: types/vue.d.ts

+35-13
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import {
77
WatchHandler,
88
DirectiveOptions,
99
DirectiveFunction,
10+
PropValidator,
11+
ThisTypedComponentOptionsWithArrayProps,
12+
ThisTypedComponentOptionsWithRecordProps,
13+
MyAsyncComponent,
1014
} from "./options";
1115
import { VNode, VNodeData, VNodeChildren, ScopedSlot } from "./vnode";
1216
import { PluginFunction, PluginObject } from "./plugin";
@@ -20,29 +24,30 @@ export type CreateElement = {
2024
(tag: string, data?: VNodeData, children?: VNodeChildren): VNode;
2125

2226
// component constructor or options
23-
(tag: Component, children: VNodeChildren): VNode;
24-
(tag: Component, data?: VNodeData, children?: VNodeChildren): VNode;
27+
(tag: Component<any, any, any, any>, children: VNodeChildren): VNode;
28+
(tag: Component<any, any, any, any>, data?: VNodeData, children?: VNodeChildren): VNode;
2529

2630
// async component
27-
(tag: AsyncComponent, children: VNodeChildren): VNode;
28-
(tag: AsyncComponent, data?: VNodeData, children?: VNodeChildren): VNode;
31+
(tag: AsyncComponent<any, any, any, any>, children: VNodeChildren): VNode;
32+
(tag: AsyncComponent<any, any, any, any>, data?: VNodeData, children?: VNodeChildren): VNode;
2933
}
3034

31-
interface AnyVue extends Vue<any, any, any> {
32-
}
35+
export interface AnyVue extends Vue<any, any, any, any> {}
36+
37+
export interface MinVue extends Vue<object, object, object, object> {}
3338

34-
export interface Vue<Data, Methods, Computed> {
39+
export interface Vue<Data, Methods, Computed, Props> {
3540
$data: Data;
3641
readonly $el: HTMLElement;
37-
readonly $options: ComponentOptions<Data, Methods, Computed>;
42+
readonly $options: ComponentOptions<Data, Methods, Computed, Props>;
3843
readonly $parent: AnyVue;
3944
readonly $root: AnyVue;
4045
readonly $children: AnyVue[];
4146
readonly $refs: { [key: string]: AnyVue | Element | AnyVue[] | Element[] };
4247
readonly $slots: { [key: string]: VNode[] };
4348
readonly $scopedSlots: { [key: string]: ScopedSlot };
4449
readonly $isServer: boolean;
45-
readonly $props: any;
50+
readonly $props: Props;
4651

4752
$mount(elementOrSelector?: Element | String, hydrating?: boolean): this;
4853
$forceUpdate(): void;
@@ -68,10 +73,19 @@ export interface Vue<Data, Methods, Computed> {
6873
$createElement: CreateElement;
6974
}
7075

76+
export type CombinedVueInstance<Data, Methods, Computed, Props> = Data & Methods & Computed & Props & Vue<Data, Methods, Computed, Props>
77+
export type ExtendedVue<Constructor extends VueConstructor, Data, Methods, Computed, Props> =
78+
(new (...args: any[]) => CombinedVueInstance<Data, Methods, Computed, Props>) &
79+
Constructor;
80+
7181
export interface VueConstructor {
72-
new <Data, Methods, Computed>(options?: ComponentOptions<Data, Methods & ThisType<Data & Methods & Computed>, Computed> & ThisType<Data & Methods & Computed>): Data & Methods & Computed & Vue<Data, Methods, Computed>;
82+
new <Data, Methods, Computed, PropNames extends string = never>(options?: ThisTypedComponentOptionsWithArrayProps<Data, Methods, Computed, PropNames>): CombinedVueInstance<Data, Methods, Computed, Record<PropNames, any>>;
83+
new <Data, Methods, Computed, Props extends Record<string, PropValidator>>(options?: ThisTypedComponentOptionsWithRecordProps<Data, Methods, Computed, Props>): CombinedVueInstance<Data, Methods, Computed, Record<keyof Props, any>>;
84+
85+
extend<VC extends VueConstructor, PropNames extends string = never>(this: VC, options: FunctionalComponentOptions<PropNames, Record<PropNames, any>>): ExtendedVue<VC, object, object, object, Record<PropNames, any>>;
86+
extend<VC extends VueConstructor, Data, Methods, Computed, PropNames extends string = never>(this: VC, options: ThisTypedComponentOptionsWithArrayProps<Data, Methods, Computed, PropNames>): ExtendedVue<VC, Data, Methods, Computed, Record<PropNames, any>>;
87+
extend<VC extends VueConstructor, Data, Methods, Computed, Props extends Record<string, PropValidator>>(this: VC, options?: ThisTypedComponentOptionsWithRecordProps<Data, Methods, Computed, Props>): ExtendedVue<VC, Data, Methods, Computed, Record<keyof Props, any>>;
7388

74-
extend<V, Data, Methods, Computed>(this: V, options: ComponentOptions<Data, Methods, Computed> | FunctionalComponentOptions): ((...args: any[]) => Vue<Data, Methods, Computed>) & V;
7589
nextTick(callback: () => void, context?: any[]): void;
7690
nextTick(): Promise<void>
7791
set<T>(object: Object, key: string, value: T): T;
@@ -83,10 +97,18 @@ export interface VueConstructor {
8397
definition?: DirectiveOptions | DirectiveFunction
8498
): DirectiveOptions;
8599
filter(id: string, definition?: Function): Function;
86-
component(id: string, definition?: Component | AsyncComponent): typeof Vue;
100+
101+
component(id: string): VueConstructor;
102+
component<VC extends VueConstructor>(id: string, constructor: VC): VC;
103+
component<VC extends VueConstructor, Data, Methods, Computed, PropNames extends string = never>(this: VC, id: string, definition: AsyncComponent<Data, Methods, Computed, PropNames>): ExtendedVue<VC, Data, Methods, Computed, Record<PropNames, any>>;
104+
component<VC extends VueConstructor, PropNames extends string = never>(this: VC, id: string, definition: FunctionalComponentOptions<PropNames, Record<PropNames, any>>): ExtendedVue<VC, {}, {}, {}, Record<PropNames, any>>;
105+
component<VC extends VueConstructor, Data, Methods, Computed, PropNames extends string = never>(this: VC, id: string, definition: ThisTypedComponentOptionsWithArrayProps<Data, Methods, Computed, PropNames>): ExtendedVue<VC, Data, Methods, Computed, Record<PropNames, any>>;
106+
component<VC extends VueConstructor, Data, Methods, Computed, Props extends Record<string, PropValidator>>(this: VC, id: string, definition?: ThisTypedComponentOptionsWithRecordProps<Data, Methods, Computed, Props>): ExtendedVue<VC, Data, Methods, Computed, Record<keyof Props, any>>;
107+
//component<VC extends VueConstructor, Data, Methods, Computed, PropNames extends string = never>(this: VC, id: string, definition: Component<Data, Methods, Computed, PropNames>): ExtendedVue<VC, Data, Methods, Computed, Record<PropNames, any>>;
108+
//component<Data, Methods, Computed, Props>(id: string, definition: Component<Data, Methods, Computed, Props> | AsyncComponent<Data, Methods, Computed, Props>): typeof Vue;
87109

88110
use<T>(plugin: PluginObject<T> | PluginFunction<T>, options?: T): void;
89-
mixin(mixin: typeof Vue | ComponentOptions<any, any, any>): void;
111+
mixin(mixin: typeof Vue | ComponentOptions<any, any, any, any>): void;
90112
compile(template: string): {
91113
render(createElement: typeof Vue.prototype.$createElement): VNode;
92114
staticRenderFns: (() => VNode)[];

0 commit comments

Comments
 (0)