Skip to content

Commit 385a744

Browse files
Allow functions in 'methods' & 'computed' to view themselves, as well as members from 'data' and the Vue instance.
1 parent 5b5a88f commit 385a744

File tree

4 files changed

+93
-68
lines changed

4 files changed

+93
-68
lines changed

Diff for: types/options.d.ts

+40-29
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,50 @@
1-
import { Vue, CreateElement } from "./vue";
1+
import { Vue, CreateElement, AnyVue } from "./vue";
22
import { VNode, VNodeData, VNodeDirective } from "./vnode";
33

44
type Constructor = {
55
new (...args: any[]): any;
66
}
77

8-
export type Component = typeof Vue | ComponentOptions<Vue> | FunctionalComponentOptions;
9-
export type AsyncComponent = (
10-
resolve: (component: Component) => void,
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,
1111
reject: (reason?: any) => void
12-
) => Promise<Component> | Component | void;
12+
) => Promise<Component<Data, Methods, Computed>> | Component<Data, Methods, Computed> | void;
13+
14+
/**
15+
* When the `Computed` type parameter on `ComponentOptions` is inferred,
16+
* it should have a property with the return type of every get-accessor.
17+
* Since there isn't a way to query for the return type of a function, we allow TypeScript
18+
* to infer from the shape of `Accessors<Computed>` and work backwards.
19+
*/
20+
export type Accessors<T> = {
21+
[K in keyof T]: (() => T[K]) | ComputedOptions<T[K]>
22+
}
1323

14-
export interface ComponentOptions<V extends Vue> {
15-
data?: Object | ((this: V) => Object);
24+
export interface ComponentOptions<Data, Methods, Computed> {
25+
data?: Data | (() => Data);
1626
props?: string[] | { [key: string]: PropOptions | Constructor | Constructor[] };
1727
propsData?: Object;
18-
computed?: { [key: string]: ((this: V) => any) | ComputedOptions<V> };
19-
methods?: { [key: string]: (this: V, ...args: any[]) => any };
20-
watch?: { [key: string]: ({ handler: WatchHandler<V, any> } & WatchOptions) | WatchHandler<V, any> | string };
28+
computed?: Accessors<Computed>;
29+
methods?: Methods;
30+
watch?: { [key: string]: ({ handler: WatchHandler<any> } & WatchOptions) | WatchHandler<any> | string };
2131

2232
el?: Element | String;
2333
template?: string;
24-
render?(this: V, createElement: CreateElement): VNode;
34+
render?(createElement: CreateElement): VNode;
2535
renderError?: (h: () => VNode, err: Error) => VNode;
2636
staticRenderFns?: ((createElement: CreateElement) => VNode)[];
2737

28-
beforeCreate?(this: V): void;
29-
created?(this: V): void;
30-
beforeDestroy?(this: V): void;
31-
destroyed?(this: V): void;
32-
beforeMount?(this: V): void;
33-
mounted?(this: V): void;
34-
beforeUpdate?(this: V): void;
35-
updated?(this: V): void;
36-
activated?(this: V): void;
37-
deactivated?(this: V): void;
38+
beforeCreate?(): void;
39+
created?(): void;
40+
beforeDestroy?(): void;
41+
destroyed?(): void;
42+
beforeMount?(): void;
43+
mounted?(): void;
44+
beforeUpdate?(): void;
45+
updated?(): void;
46+
activated?(): void;
47+
deactivated?(): void;
3848

3949
directives?: { [key: string]: DirectiveOptions | DirectiveFunction };
4050
components?: { [key: string]: Component | AsyncComponent };
@@ -49,10 +59,11 @@ export interface ComponentOptions<V extends Vue> {
4959
event?: string;
5060
};
5161

52-
parent?: Vue;
53-
mixins?: (ComponentOptions<Vue> | typeof Vue)[];
62+
parent?: AnyVue;
63+
mixins?: (ComponentOptions<any, any, any> | typeof Vue)[];
5464
name?: string;
55-
extends?: ComponentOptions<Vue> | typeof Vue;
65+
// TODO: support properly inferred 'extends'
66+
extends?: ComponentOptions<any, any, any> | typeof Vue;
5667
delimiters?: [string, string];
5768
}
5869

@@ -68,7 +79,7 @@ export interface RenderContext {
6879
children: VNode[];
6980
slots(): any;
7081
data: VNodeData;
71-
parent: Vue;
82+
parent: AnyVue;
7283
}
7384

7485
export interface PropOptions {
@@ -78,13 +89,13 @@ export interface PropOptions {
7889
validator?(value: any): boolean;
7990
}
8091

81-
export interface ComputedOptions<V> {
82-
get?(this: V): any;
83-
set?(this: V, value: any): void;
92+
export interface ComputedOptions<T> {
93+
get?(): T;
94+
set?(value: T): void;
8495
cache?: boolean;
8596
}
8697

87-
export type WatchHandler<V, T> = (this: V, val: T, oldVal: T) => void;
98+
export type WatchHandler<T> = (val: T, oldVal: T) => void;
8899

89100
export interface WatchOptions {
90101
deep?: boolean;

Diff for: types/test/augmentation-test.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@ import Vue from "../index";
22

33
declare module "../vue" {
44
// add instance property and method
5-
interface Vue {
5+
interface Vue<Data, Methods, Computed> {
66
$instanceProperty: string;
77
$instanceMethod(): void;
88
}
99

1010
// add static property and method
11-
namespace Vue {
12-
const staticProperty: string;
13-
function staticMethod(): void;
11+
interface VueConstructor {
12+
staticProperty: string;
13+
staticMethod(): void;
1414
}
1515
}
1616

1717
// augment ComponentOptions
1818
declare module "../options" {
19-
interface ComponentOptions<V extends Vue> {
19+
interface ComponentOptions<Data, Methods, Computed> {
2020
foo?: string;
2121
}
2222
}

Diff for: types/tsconfig.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"strict": true,
4+
"lib": [
5+
"es2015", "dom"
6+
]
7+
}
8+
}

Diff for: types/vue.d.ts

+40-34
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
WatchOptions,
77
WatchHandler,
88
DirectiveOptions,
9-
DirectiveFunction
9+
DirectiveFunction,
1010
} from "./options";
1111
import { VNode, VNodeData, VNodeChildren, ScopedSlot } from "./vnode";
1212
import { PluginFunction, PluginObject } from "./plugin";
@@ -28,17 +28,17 @@ export type CreateElement = {
2828
(tag: AsyncComponent, data?: VNodeData, children?: VNodeChildren): VNode;
2929
}
3030

31-
export declare class Vue {
32-
33-
constructor(options?: ComponentOptions<Vue>);
31+
interface AnyVue extends Vue<any, any, any> {
32+
}
3433

35-
$data: Object;
34+
export interface Vue<Data, Methods, Computed> {
35+
$data: Data;
3636
readonly $el: HTMLElement;
37-
readonly $options: ComponentOptions<this>;
38-
readonly $parent: Vue;
39-
readonly $root: Vue;
40-
readonly $children: Vue[];
41-
readonly $refs: { [key: string]: Vue | Element | Vue[] | Element[]};
37+
readonly $options: ComponentOptions<Data, Methods, Computed>;
38+
readonly $parent: AnyVue;
39+
readonly $root: AnyVue;
40+
readonly $children: AnyVue[];
41+
readonly $refs: { [key: string]: AnyVue | Element | AnyVue[] | Element[] };
4242
readonly $slots: { [key: string]: VNode[] };
4343
readonly $scopedSlots: { [key: string]: ScopedSlot };
4444
readonly $isServer: boolean;
@@ -51,12 +51,12 @@ export declare class Vue {
5151
$delete: typeof Vue.delete;
5252
$watch(
5353
expOrFn: string,
54-
callback: WatchHandler<this, any>,
54+
callback: WatchHandler<any>,
5555
options?: WatchOptions
5656
): (() => void);
5757
$watch<T>(
5858
expOrFn: (this: this) => T,
59-
callback: WatchHandler<this, T>,
59+
callback: WatchHandler<T>,
6060
options?: WatchOptions
6161
): (() => void);
6262
$on(event: string | string[], callback: Function): this;
@@ -66,36 +66,42 @@ export declare class Vue {
6666
$nextTick(callback: (this: this) => void): void;
6767
$nextTick(): Promise<void>;
6868
$createElement: CreateElement;
69+
}
6970

70-
static config: {
71-
silent: boolean;
72-
optionMergeStrategies: any;
73-
devtools: boolean;
74-
productionTip: boolean;
75-
performance: boolean;
76-
errorHandler(err: Error, vm: Vue, info: string): void;
77-
ignoredElements: string[];
78-
keyCodes: { [key: string]: number };
79-
}
71+
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>;
8073

81-
static extend(options: ComponentOptions<Vue> | FunctionalComponentOptions): typeof Vue;
82-
static nextTick(callback: () => void, context?: any[]): void;
83-
static nextTick(): Promise<void>
84-
static set<T>(object: Object, key: string, value: T): T;
85-
static set<T>(array: T[], key: number, value: T): T;
86-
static delete(object: Object, key: string): void;
74+
extend<V, Data, Methods, Computed>(this: V, options: ComponentOptions<Data, Methods, Computed> | FunctionalComponentOptions): ((...args: any[]) => Vue<Data, Methods, Computed>) & V;
75+
nextTick(callback: () => void, context?: any[]): void;
76+
nextTick(): Promise<void>
77+
set<T>(object: Object, key: string, value: T): T;
78+
set<T>(array: T[], key: number, value: T): T;
79+
delete(object: Object, key: string): void;
8780

88-
static directive(
81+
directive(
8982
id: string,
9083
definition?: DirectiveOptions | DirectiveFunction
9184
): DirectiveOptions;
92-
static filter(id: string, definition?: Function): Function;
93-
static component(id: string, definition?: Component | AsyncComponent): typeof Vue;
85+
filter(id: string, definition?: Function): Function;
86+
component(id: string, definition?: Component | AsyncComponent): typeof Vue;
9487

95-
static use<T>(plugin: PluginObject<T> | PluginFunction<T>, options?: T): void;
96-
static mixin(mixin: typeof Vue | ComponentOptions<Vue>): void;
97-
static compile(template: string): {
88+
use<T>(plugin: PluginObject<T> | PluginFunction<T>, options?: T): void;
89+
mixin(mixin: typeof Vue | ComponentOptions<any, any, any>): void;
90+
compile(template: string): {
9891
render(createElement: typeof Vue.prototype.$createElement): VNode;
9992
staticRenderFns: (() => VNode)[];
10093
};
94+
95+
config: {
96+
silent: boolean;
97+
optionMergeStrategies: any;
98+
devtools: boolean;
99+
productionTip: boolean;
100+
performance: boolean;
101+
errorHandler(err: Error, vm: AnyVue, info: string): void;
102+
ignoredElements: string[];
103+
keyCodes: { [key: string]: number };
104+
}
101105
}
106+
107+
export const Vue: VueConstructor;

0 commit comments

Comments
 (0)