Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Further improve Vue type declarations for canonical usage #6391

Merged
merged 56 commits into from
Oct 6, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
5b5a88f
refactor TypeScript typings to use ES style exports
yyx990803 Feb 26, 2017
385a744
Allow functions in 'methods' & 'computed' to view themselves, as well…
DanielRosenwasser Mar 8, 2017
8cd5b9c
Got 'new Vue(...)', 'Vue.extend(...)', and 'Vue.component(...)' working.
DanielRosenwasser Mar 16, 2017
540a38f
Made it so that any 'data' function can only access 'props' and base …
DanielRosenwasser Mar 27, 2017
f34f4f6
Improved defaults, fixed overloads and types for functional component…
DanielRosenwasser Jun 1, 2017
b1f40ce
Condensed declaration of 'watch'.
DanielRosenwasser Jun 1, 2017
355ff75
Added two tests for 'extend'.
DanielRosenwasser Jun 1, 2017
bc54007
.\types\options.d.ts
DanielRosenwasser Jun 1, 2017
e7ea5bb
Updated tests, tighted strictness.
DanielRosenwasser Jun 1, 2017
ebde0b1
Merge remote-tracking branch 'upstream/dev' into accurateVueTypes
DanielRosenwasser Jun 1, 2017
d78d14b
Made the Vue instance non-generic, made readonly, augmented tests.
DanielRosenwasser Jun 14, 2017
fc83771
Make it possible to extend Vue without type arguments.
DanielRosenwasser Jun 14, 2017
a50c838
Removed 'ThisTypedComponentOptions'.
DanielRosenwasser Jun 14, 2017
3c86b10
Merge remote-tracking branch 'upstream/dev' into accurateVueTypes
DanielRosenwasser Jun 14, 2017
33a106c
Upgraded dependency on TypeScript.
DanielRosenwasser Jun 15, 2017
0f586db
Added test by @ktsn.
DanielRosenwasser Jun 15, 2017
1092efe
Removed unnecessary mixin constructors, made 'VueConstructor' generic.
DanielRosenwasser Jun 15, 2017
ebd8c0b
Merge remote-tracking branch 'upstream/dev' into accurateVueTypes
DanielRosenwasser Jun 23, 2017
c628103
[release] weex-vue-framework@2.4.2-weex.1 (#6196)
Hanks10100 Jul 24, 2017
e4a8545
Merge remote-tracking branch 'upstream/dev' into accurateVueTypes
DanielRosenwasser Jul 28, 2017
3cac5c7
fix-Firefox (#6359)
HiWangyeah Aug 13, 2017
d55bc63
feat(typing): compatible interface declaration
HerringtonDarkholme Aug 16, 2017
07eb21c
improve typing and tests
HerringtonDarkholme Aug 16, 2017
e7777d7
Merge branch 'new-type' of github.com:HerringtonDarkholme/vue into ne…
HerringtonDarkholme Aug 17, 2017
21d62a1
fix(typing): change default computed typing
HerringtonDarkholme Aug 17, 2017
0958bda
feat(typing): add more specific prop typing
HerringtonDarkholme Aug 17, 2017
6c76c45
feat(typing): refine props
HerringtonDarkholme Aug 17, 2017
5335788
fix(typing): fix some typing errors
HerringtonDarkholme Aug 17, 2017
8a1aab2
fix(typing): add async component back
HerringtonDarkholme Aug 17, 2017
042e1c3
test(typing): add small granular test
HerringtonDarkholme Aug 17, 2017
76de5dc
feat(typing): add ArrayProp back
HerringtonDarkholme Aug 17, 2017
070460b
feat(typing): add array types back
HerringtonDarkholme Aug 17, 2017
718dd7d
feat(typing): add array prop to extend/component
HerringtonDarkholme Aug 17, 2017
89f958b
feat(typing): add string prop test
HerringtonDarkholme Aug 17, 2017
da53a0a
fix(typing): add more compatibility test
HerringtonDarkholme Aug 17, 2017
e034641
fix(typing): address code review feedback
HerringtonDarkholme Aug 20, 2017
c9f0939
fix(typing): add cyclic test case
HerringtonDarkholme Aug 20, 2017
754d0df
feat(typing): add union type test
HerringtonDarkholme Aug 20, 2017
b784785
feat(typing): use call signatures
HerringtonDarkholme Aug 26, 2017
d5fbd81
fix(typing): add tests for regexp and array
HerringtonDarkholme Aug 28, 2017
37c5883
feat(typing): label props as readonly
HerringtonDarkholme Aug 29, 2017
9e6931a
fix(typing): this in beforeCreate is plain Vue
HerringtonDarkholme Aug 29, 2017
d9accb0
fix(typing): fix beforeCreate test
HerringtonDarkholme Aug 29, 2017
b90386a
fix(typing): use extended typing
HerringtonDarkholme Aug 29, 2017
67eab9c
chore: update backers
yyx990803 Aug 3, 2017
97a401e
Merge branch 'dev' of github.com:vuejs/vue into new-type
HerringtonDarkholme Aug 29, 2017
8df15b7
Merge branch 'dev' of github.com:vuejs/vue into new-type
HerringtonDarkholme Sep 6, 2017
1ac0b7a
Merge branch 'new-type' of github.com:HerringtonDarkholme/vue into ne…
HerringtonDarkholme Sep 6, 2017
4649739
Simplify 'CreateElement', remove potential error in 'AsyncComponent' …
DanielRosenwasser Sep 9, 2017
c953990
Simplify down to two overloads.
DanielRosenwasser Sep 11, 2017
8901752
Merge pull request #1 from DanielRosenwasser/simplifyCreateElement
HerringtonDarkholme Sep 12, 2017
a7f84d9
Merge branch 'dev' of github.com:vuejs/vue into new-type
HerringtonDarkholme Sep 14, 2017
5fa1ab9
Merge branch 'new-type' of github.com:HerringtonDarkholme/vue into ne…
HerringtonDarkholme Sep 14, 2017
a595239
fix(typing): fix functional component typing
HerringtonDarkholme Sep 14, 2017
00aa9d3
Merge branch 'dev' of github.com:vuejs/vue into new-type
HerringtonDarkholme Sep 17, 2017
6091248
Merge branch 'dev' of github.com:vuejs/vue into new-type
HerringtonDarkholme Sep 18, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Allow functions in 'methods' & 'computed' to view themselves, as well…
… as members from 'data' and the Vue instance.
  • Loading branch information
DanielRosenwasser committed Mar 8, 2017
commit 385a74463bba9b76c9f2cfd6452ee40590a9d56f
69 changes: 40 additions & 29 deletions types/options.d.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,50 @@
import { Vue, CreateElement } from "./vue";
import { Vue, CreateElement, AnyVue } from "./vue";
import { VNode, VNodeData, VNodeDirective } from "./vnode";

type Constructor = {
new (...args: any[]): any;
}

export type Component = typeof Vue | ComponentOptions<Vue> | FunctionalComponentOptions;
export type AsyncComponent = (
resolve: (component: Component) => void,
export type Component<Data = any, Methods = any, Computed = any> = typeof Vue | ComponentOptions<Data, Methods, Computed> | FunctionalComponentOptions;
export type AsyncComponent<Data = any, Methods = any, Computed = any> = (
resolve: (component: Component<Data, Methods, Computed>) => void,
reject: (reason?: any) => void
) => Promise<Component> | Component | void;
) => Promise<Component<Data, Methods, Computed>> | Component<Data, Methods, Computed> | void;

/**
* When the `Computed` type parameter on `ComponentOptions` is inferred,
* it should have a property with the return type of every get-accessor.
* Since there isn't a way to query for the return type of a function, we allow TypeScript
* to infer from the shape of `Accessors<Computed>` and work backwards.
*/
export type Accessors<T> = {
[K in keyof T]: (() => T[K]) | ComputedOptions<T[K]>
}

export interface ComponentOptions<V extends Vue> {
data?: Object | ((this: V) => Object);
export interface ComponentOptions<Data, Methods, Computed> {
data?: Data | (() => Data);
props?: string[] | { [key: string]: PropOptions | Constructor | Constructor[] };
propsData?: Object;
computed?: { [key: string]: ((this: V) => any) | ComputedOptions<V> };
methods?: { [key: string]: (this: V, ...args: any[]) => any };
watch?: { [key: string]: ({ handler: WatchHandler<V, any> } & WatchOptions) | WatchHandler<V, any> | string };
computed?: Accessors<Computed>;
methods?: Methods;
watch?: { [key: string]: ({ handler: WatchHandler<any> } & WatchOptions) | WatchHandler<any> | string };

el?: Element | String;
template?: string;
render?(this: V, createElement: CreateElement): VNode;
render?(createElement: CreateElement): VNode;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like ThisType of computed, watch, render and lifecycle hooks will be invalid if the users annotate their component options with as ComponentOptions<Something>.
Can we deal with in that case too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type assertion like { opt: ...} as Option would not bring type inference to the declaration.
Users have to annotate Vue.extend or casting this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Then I think we should stated about this in docs for migration 🙂

renderError?: (h: () => VNode, err: Error) => VNode;
staticRenderFns?: ((createElement: CreateElement) => VNode)[];

beforeCreate?(this: V): void;
created?(this: V): void;
beforeDestroy?(this: V): void;
destroyed?(this: V): void;
beforeMount?(this: V): void;
mounted?(this: V): void;
beforeUpdate?(this: V): void;
updated?(this: V): void;
activated?(this: V): void;
deactivated?(this: V): void;
beforeCreate?(): void;
created?(): void;
beforeDestroy?(): void;
destroyed?(): void;
beforeMount?(): void;
mounted?(): void;
beforeUpdate?(): void;
updated?(): void;
activated?(): void;
deactivated?(): void;

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

parent?: Vue;
mixins?: (ComponentOptions<Vue> | typeof Vue)[];
parent?: AnyVue;
mixins?: (ComponentOptions<any, any, any> | typeof Vue)[];
name?: string;
extends?: ComponentOptions<Vue> | typeof Vue;
// TODO: support properly inferred 'extends'
extends?: ComponentOptions<any, any, any> | typeof Vue;
delimiters?: [string, string];
}

Expand All @@ -68,7 +79,7 @@ export interface RenderContext {
children: VNode[];
slots(): any;
data: VNodeData;
parent: Vue;
parent: AnyVue;
}

export interface PropOptions {
Expand All @@ -78,13 +89,13 @@ export interface PropOptions {
validator?(value: any): boolean;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we let value type to T since we can infer prop type now?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of validator is testing anything if it is of type T, so any is more appropriate here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But at least its type is specified by type option, isn't it?
The other types than type is not come here on runtime.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, I forget there is builtin check before validator!

}

export interface ComputedOptions<V> {
get?(this: V): any;
set?(this: V, value: any): void;
export interface ComputedOptions<T> {
get?(): T;
set?(value: T): void;
cache?: boolean;
}

export type WatchHandler<V, T> = (this: V, val: T, oldVal: T) => void;
export type WatchHandler<T> = (val: T, oldVal: T) => void;

export interface WatchOptions {
deep?: boolean;
Expand Down
10 changes: 5 additions & 5 deletions types/test/augmentation-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ import Vue from "../index";

declare module "../vue" {
// add instance property and method
interface Vue {
interface Vue<Data, Methods, Computed> {
$instanceProperty: string;
$instanceMethod(): void;
}

// add static property and method
namespace Vue {
const staticProperty: string;
function staticMethod(): void;
interface VueConstructor {
staticProperty: string;
staticMethod(): void;
}
}

// augment ComponentOptions
declare module "../options" {
interface ComponentOptions<V extends Vue> {
interface ComponentOptions<Data, Methods, Computed> {
foo?: string;
}
}
Expand Down
8 changes: 8 additions & 0 deletions types/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"strict": true,
"lib": [
"es2015", "dom"
]
}
}
74 changes: 40 additions & 34 deletions types/vue.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
WatchOptions,
WatchHandler,
DirectiveOptions,
DirectiveFunction
DirectiveFunction,
} from "./options";
import { VNode, VNodeData, VNodeChildren, ScopedSlot } from "./vnode";
import { PluginFunction, PluginObject } from "./plugin";
Expand All @@ -28,17 +28,17 @@ export type CreateElement = {
(tag: AsyncComponent, data?: VNodeData, children?: VNodeChildren): VNode;
}

export declare class Vue {

constructor(options?: ComponentOptions<Vue>);
interface AnyVue extends Vue<any, any, any> {
}

$data: Object;
export interface Vue<Data, Methods, Computed> {
$data: Data;
readonly $el: HTMLElement;
readonly $options: ComponentOptions<this>;
readonly $parent: Vue;
readonly $root: Vue;
readonly $children: Vue[];
readonly $refs: { [key: string]: Vue | Element | Vue[] | Element[]};
readonly $options: ComponentOptions<Data, Methods, Computed>;
readonly $parent: AnyVue;
readonly $root: AnyVue;
readonly $children: AnyVue[];
readonly $refs: { [key: string]: AnyVue | Element | AnyVue[] | Element[] };
readonly $slots: { [key: string]: VNode[] };
readonly $scopedSlots: { [key: string]: ScopedSlot };
readonly $isServer: boolean;
Expand All @@ -51,12 +51,12 @@ export declare class Vue {
$delete: typeof Vue.delete;
$watch(
expOrFn: string,
callback: WatchHandler<this, any>,
callback: WatchHandler<any>,
options?: WatchOptions
): (() => void);
$watch<T>(
expOrFn: (this: this) => T,
callback: WatchHandler<this, T>,
callback: WatchHandler<T>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, we need to keep WatchHandler's ThisType?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. We cannot reuse WatchHandler because explicit this typing will break ThisType. Just write a new function type will be fine.

options?: WatchOptions
): (() => void);
$on(event: string | string[], callback: Function): this;
Expand All @@ -66,36 +66,42 @@ export declare class Vue {
$nextTick(callback: (this: this) => void): void;
$nextTick(): Promise<void>;
$createElement: CreateElement;
}

static config: {
silent: boolean;
optionMergeStrategies: any;
devtools: boolean;
productionTip: boolean;
performance: boolean;
errorHandler(err: Error, vm: Vue, info: string): void;
ignoredElements: string[];
keyCodes: { [key: string]: number };
}
export interface VueConstructor {
new <Data, Methods, Computed>(options?: ComponentOptions<Data, Methods & ThisType<Data & Methods & Computed>, Computed> & ThisType<Data & Methods & Computed>): Data & Methods & Computed & Vue<Data, Methods, Computed>;

static extend(options: ComponentOptions<Vue> | FunctionalComponentOptions): typeof Vue;
static nextTick(callback: () => void, context?: any[]): void;
static nextTick(): Promise<void>
static set<T>(object: Object, key: string, value: T): T;
static set<T>(array: T[], key: number, value: T): T;
static delete(object: Object, key: string): void;
extend<V, Data, Methods, Computed>(this: V, options: ComponentOptions<Data, Methods, Computed> | FunctionalComponentOptions): ((...args: any[]) => Vue<Data, Methods, Computed>) & V;
nextTick(callback: () => void, context?: any[]): void;
nextTick(): Promise<void>
set<T>(object: Object, key: string, value: T): T;
set<T>(array: T[], key: number, value: T): T;
delete(object: Object, key: string): void;

static directive(
directive(
id: string,
definition?: DirectiveOptions | DirectiveFunction
): DirectiveOptions;
static filter(id: string, definition?: Function): Function;
static component(id: string, definition?: Component | AsyncComponent): typeof Vue;
filter(id: string, definition?: Function): Function;
component(id: string, definition?: Component | AsyncComponent): typeof Vue;

static use<T>(plugin: PluginObject<T> | PluginFunction<T>, options?: T): void;
static mixin(mixin: typeof Vue | ComponentOptions<Vue>): void;
static compile(template: string): {
use<T>(plugin: PluginObject<T> | PluginFunction<T>, options?: T): void;
mixin(mixin: typeof Vue | ComponentOptions<any, any, any>): void;
compile(template: string): {
render(createElement: typeof Vue.prototype.$createElement): VNode;
staticRenderFns: (() => VNode)[];
};

config: {
silent: boolean;
optionMergeStrategies: any;
devtools: boolean;
productionTip: boolean;
performance: boolean;
errorHandler(err: Error, vm: AnyVue, info: string): void;
ignoredElements: string[];
keyCodes: { [key: string]: number };
}
}

export const Vue: VueConstructor;