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 all commits
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)
wang-jian-zhong 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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"eslint": "^3.0.0",
"eslint-loader": "^1.7.1",
"eslint-plugin-flowtype": "^2.34.0",
"eslint-plugin-jasmine": "^2.2.0",
"eslint-plugin-jasmine": "^2.8.4",
"eslint-plugin-vue-libs": "^1.2.0",
"file-loader": "^0.11.2",
"flow-bin": "^0.48.0",
Expand Down Expand Up @@ -119,7 +119,7 @@
"selenium-server": "^2.53.1",
"serialize-javascript": "^1.3.0",
"shelljs": "^0.7.8",
"typescript": "^2.3.4",
"typescript": "^2.5.2",
"uglify-js": "^3.0.15",
"webpack": "^2.6.1",
"weex-js-runtime": "^0.20.5",
Expand Down
63 changes: 31 additions & 32 deletions types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,36 @@
import * as V from "./vue";
import * as Options from "./options";
import * as Plugin from "./plugin";
import * as VNode from "./vnode";
import { Vue } from "./vue";

// `Vue` in `export = Vue` must be a namespace
// All available types are exported via this namespace
declare namespace Vue {
export type CreateElement = V.CreateElement;
export default Vue;

export type Component = Options.Component;
export type AsyncComponent = Options.AsyncComponent;
export type ComponentOptions<V extends Vue> = Options.ComponentOptions<V>;
export type FunctionalComponentOptions = Options.FunctionalComponentOptions;
export type RenderContext = Options.RenderContext;
export type PropOptions = Options.PropOptions;
export type ComputedOptions<V extends Vue> = Options.ComputedOptions<V>;
export type WatchHandler<V extends Vue> = Options.WatchHandler<V, any>;
export type WatchOptions = Options.WatchOptions;
export type DirectiveFunction = Options.DirectiveFunction;
export type DirectiveOptions = Options.DirectiveOptions;
export {
CreateElement
} from "./vue";

export type PluginFunction<T> = Plugin.PluginFunction<T>;
export type PluginObject<T> = Plugin.PluginObject<T>;
export {
Component,
AsyncComponent,
ComponentOptions,
FunctionalComponentOptions,
RenderContext,
PropOptions,
ComputedOptions,
WatchHandler,
WatchOptions,
WatchOptionsWithHandler,
DirectiveFunction,
DirectiveOptions
} from "./options";

export type VNodeChildren = VNode.VNodeChildren;
export type VNodeChildrenArrayContents = VNode.VNodeChildrenArrayContents;
export type VNode = VNode.VNode;
export type VNodeComponentOptions = VNode.VNodeComponentOptions;
export type VNodeData = VNode.VNodeData;
export type VNodeDirective = VNode.VNodeDirective;
}
export {
PluginFunction,
PluginObject
} from "./plugin";

// TS cannot merge imported class with namespace, declare a subclass to bypass
declare class Vue extends V.Vue {}

export = Vue;
export {
VNodeChildren,
VNodeChildrenArrayContents,
VNode,
VNodeComponentOptions,
VNodeData,
VNodeDirective
} from "./vnode";
129 changes: 92 additions & 37 deletions types/options.d.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,88 @@
import { Vue, CreateElement } from "./vue";
import { Vue, CreateElement, CombinedVueInstance } from "./vue";
import { VNode, VNodeData, VNodeDirective } from "./vnode";

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

export type Component = typeof Vue | ComponentOptions<Vue> | FunctionalComponentOptions;
// we don't support infer props in async component
export type Component<Data=DefaultData<Vue>, Methods=DefaultMethods<Vue>, Computed=DefaultComputed, Props=DefaultProps> =
| typeof Vue
| FunctionalComponentOptions<Props>
| ThisTypedComponentOptionsWithArrayProps<Vue, Data, Methods, Computed, keyof Props>
| ThisTypedComponentOptionsWithRecordProps<Vue, Data, Methods, Computed, Props>;

interface EsModuleComponent {
default: Component
}

export type AsyncComponent = (
resolve: (component: Component) => void,
export type AsyncComponent<Data=DefaultData<Vue>, Methods=DefaultMethods<Vue>, Computed=DefaultComputed, Props=DefaultProps> = (
resolve: (component: Component<Data, Methods, Computed, Props>) => void,
reject: (reason?: any) => void
) => Promise<Component | EsModuleComponent> | Component | void;
) => Promise<Component | EsModuleComponent> | 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);
props?: string[] | { [key: string]: PropOptions | Constructor | Constructor[] };
/**
* This type should be used when an array of strings is used for a component's `props` value.
*/
export type ThisTypedComponentOptionsWithArrayProps<V extends Vue, Data, Methods, Computed, PropNames extends string> =
object &
ComponentOptions<V, Data | ((this: Readonly<Record<PropNames, any>> & V) => Data), Methods, Computed, PropNames[]> &
ThisType<CombinedVueInstance<V, Data, Methods, Computed, Readonly<Record<PropNames, any>>>>;

/**
* This type should be used when an object mapped to `PropOptions` is used for a component's `props` value.
*/
export type ThisTypedComponentOptionsWithRecordProps<V extends Vue, Data, Methods, Computed, Props> =
object &
ComponentOptions<V, Data | ((this: Readonly<Props> & V) => Data), Methods, Computed, RecordPropsDefinition<Props>> &
ThisType<CombinedVueInstance<V, Data, Methods, Computed, Readonly<Props>>>;

type DefaultData<V> = object | ((this: V) => object);
type DefaultProps = Record<string, any>;
type DefaultMethods<V> = { [key: string]: (this: V, ...args: any[]) => any };
type DefaultComputed = { [key: string]: any };
export interface ComponentOptions<
V extends Vue,
Data=DefaultData<V>,
Methods=DefaultMethods<V>,
Computed=DefaultComputed,
PropsDef=PropsDefinition<DefaultProps>> {
data?: Data;
props?: PropsDef;
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?: Record<string, WatchOptionsWithHandler<any> | 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;

directives?: { [key: string]: DirectiveOptions | DirectiveFunction };
components?: { [key: string]: Component | AsyncComponent };
created?(): void;
beforeDestroy?(): void;
destroyed?(): void;
beforeMount?(): void;
mounted?(): void;
beforeUpdate?(): void;
updated?(): void;
activated?(): void;
deactivated?(): void;

directives?: { [key: string]: DirectiveFunction | DirectiveOptions };
components?: { [key: string]: Component<any, any, any, any> | AsyncComponent<any, any, any, any> };
transitions?: { [key: string]: Object };
filters?: { [key: string]: Function };

Expand All @@ -57,49 +97,64 @@ export interface ComponentOptions<V extends Vue> {
parent?: Vue;
mixins?: (ComponentOptions<Vue> | typeof Vue)[];
name?: string;
// TODO: support properly inferred 'extends'
extends?: ComponentOptions<Vue> | typeof Vue;
delimiters?: [string, string];
comments?: boolean;
inheritAttrs?: boolean;
}

export interface FunctionalComponentOptions {
export interface FunctionalComponentOptions<Props = DefaultProps, PropDefs = PropsDefinition<Props>> {
name?: string;
props?: string[] | { [key: string]: PropOptions | Constructor | Constructor[] };
props?: PropDefs;
inject?: { [key: string]: string | symbol } | string[];
functional: boolean;
render(this: never, createElement: CreateElement, context: RenderContext): VNode | void;
render(this: undefined, createElement: CreateElement, context: RenderContext<Props>): VNode;
}

export interface RenderContext {
props: any;
export interface RenderContext<Props=DefaultProps> {
props: Props;
children: VNode[];
slots(): any;
data: VNodeData;
parent: Vue;
injections: any
}

export interface PropOptions {
type?: Constructor | Constructor[] | null;
export type Prop<T> = { (): T } | { new (...args: any[]): T & object }

export type PropValidator<T> = PropOptions<T> | Prop<T> | Prop<T>[];

export interface PropOptions<T=any> {
type?: Prop<T> | Prop<T>[];
Copy link
Member

Choose a reason for hiding this comment

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

This is clever declaration :D

required?: boolean;
default?: any;
validator?(value: any): boolean;
default?: T | null | undefined | (() => object);
validator?(value: T): boolean;
}

export interface ComputedOptions<V> {
get?(this: V): any;
set?(this: V, value: any): void;
export type RecordPropsDefinition<T> = {
[K in keyof T]: PropValidator<T[K]>
}
export type ArrayPropsDefinition<T> = (keyof T)[];
export type PropsDefinition<T> = ArrayPropsDefinition<T> | RecordPropsDefinition<T>;

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;
immediate?: boolean;
}

export interface WatchOptionsWithHandler<T> extends WatchOptions {
handler: WatchHandler<T>;
}

export type DirectiveFunction = (
el: HTMLElement,
binding: VNodeDirective,
Expand Down
21 changes: 16 additions & 5 deletions types/test/augmentation-test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Vue = require("../index");
import Vue from "../index";

declare module "../vue" {
// add instance property and method
Expand All @@ -8,9 +8,9 @@ declare module "../vue" {
}

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

Expand All @@ -22,10 +22,21 @@ declare module "../options" {
}

const vm = new Vue({
props: ["bar"],
data: {
a: true
},
foo: "foo"
Copy link
Member

Choose a reason for hiding this comment

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

We should keep this line to test ComponentOptions augmentation?

Copy link
Member Author

Choose a reason for hiding this comment

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

Oops, unintentional deletion during refactoring. Thanks for pointing out!

foo: "foo",
methods: {
foo() {
this.a = false;
}
},
computed: {
BAR(): string {
return this.bar.toUpperCase();
}
}
});

vm.$instanceProperty;
Expand Down
Loading