Просмотр исходного кода

Add TypeScript definitions

Add TypeScript definition

Remove unnecessary definition

Update definitions

* separate files
* remove unnecessary `{[key: string]: any}`
* from singular to plural

Update definitions

* Add more definitions
* Rename filename and interface
* Sort definitions
* Fix indent

Fix

Add test

* add test
* fix some definitions
* fix typo

Fix ComputedOptions

Update Vue.set

Update definitions

Add npm script
kaorun343 9 лет назад
Родитель
Сommit
dfc64e8a11

+ 2 - 1
package.json

@@ -17,12 +17,13 @@
     "dev:compiler": "TARGET=web-compiler rollup -w -c build/config.js",
     "build": "node build/build.js",
     "build:ssr": "npm run build -- vue.common.js,vue-server-renderer",
-    "test": "npm run lint && flow check && npm run test:cover && npm run test:e2e -- --env phantomjs && npm run test:ssr",
+    "test": "npm run lint && flow check && npm run test:types && npm run test:cover && npm run test:e2e -- --env phantomjs && npm run test:ssr",
     "test:unit": "karma start build/karma.unit.config.js",
     "test:cover": "karma start build/karma.cover.config.js",
     "test:e2e": "npm run build -- vue.js && node test/e2e/runner.js",
     "test:ssr": "npm run build:ssr && VUE_ENV=server jasmine JASMINE_CONFIG_PATH=test/ssr/jasmine.json",
     "test:sauce": "npm run sauce -- 0 && npm run sauce -- 1 && npm run sauce -- 2",
+    "test:types": "tsc -p ./types/test/tsconfig.json",
     "lint": "eslint src build test",
     "flow": "flow check",
     "sauce": "SAUCE=true karma start build/karma.sauce.config.js",

+ 2 - 0
types/index.d.ts

@@ -0,0 +1,2 @@
+import {Vue} from "./vue.d";
+export = Vue;

+ 74 - 0
types/options.d.ts

@@ -0,0 +1,74 @@
+import { Vue } from "./vue.d";
+import { VNode, VNodeDirective } from "./vnode.d";
+
+type Constructor = {
+  new (...args: any[]): any;
+}
+
+export interface ComponentOptions {
+  data?: Object | ( (this: Vue) => Object );
+  props?: string[] | { [key: string]: PropOptions | Constructor | Constructor[] };
+  propsData?: Object;
+  computed?: { [key: string]: ((this: Vue) => any) | ComputedOptions };
+  methods?: { [key: string]: Function };
+  watch?: { [key: string]: ({ handler: WatchHandler } & WatchOptions) | WatchHandler | string };
+
+  el?: Element | String;
+  template?: string;
+  render?(createElement: typeof Vue.prototype.$createElement): VNode;
+  staticRenderFns?: (() => VNode)[];
+
+  beforeCreate?(): void;
+  created?(): void;
+  beforeDestroy?(): void;
+  destroyed?(): void;
+  beforeMount?(): void;
+  mounted?(): void;
+  beforeUpdate?(): void;
+  updated?(): void;
+
+  directives?: { [key: string]: DirectiveOptions | DirectiveFunction };
+  components?: { [key: string]: ComponentOptions | typeof Vue };
+  transitions?: { [key: string]: Object };
+  filters?: { [key: string]: Function };
+
+  parent?: Vue;
+  mixins?: (ComponentOptions | typeof Vue)[];
+  name?: string;
+  extends?: ComponentOptions | typeof Vue;
+  delimiters?: [string, string];
+}
+
+export interface PropOptions {
+  type?: Constructor | Constructor[] | null;
+  required?: boolean;
+  default?: any;
+  validator?(value: any): boolean;
+}
+
+export interface ComputedOptions {
+  get?(this: Vue): any;
+  set?(this: Vue, value: any): void;
+  cache?: boolean;
+}
+
+export type WatchHandler = <T>(val: T, oldVal: T) => void;
+
+export interface WatchOptions {
+  deep?: boolean;
+  immediate?: boolean;
+}
+
+export type DirectiveFunction = (
+  el: HTMLElement,
+  binding: VNodeDirective,
+  vnode: VNode,
+  oldVnode: VNode
+) => void;
+
+export interface DirectiveOptions {
+  bind?: DirectiveFunction;
+  update?: DirectiveFunction;
+  componentUpdated?: DirectiveFunction;
+  unbind?: DirectiveFunction;
+}

+ 8 - 0
types/plugin.d.ts

@@ -0,0 +1,8 @@
+import { Vue as _Vue } from "./vue.d";
+
+export type PluginFunction<T> = (Vue: typeof _Vue, options?: T) => void;
+
+export interface PluginObject<T> {
+  install: PluginFunction<T>;
+  [key: string]: any;
+}

+ 136 - 0
types/test/options-test.ts

@@ -0,0 +1,136 @@
+import { Vue } from "../vue.d";
+import { ComponentOptions } from "../options.d";
+
+interface Component extends Vue {
+  a: number;
+}
+
+const Options: ComponentOptions = {
+  data() {
+    return {
+      a: 1
+    }
+  },
+  props: {
+    size: Number,
+    name: {
+      type: String,
+      default: 0,
+      required: true,
+      validator(value) {
+        return value > 0;
+      }
+    }
+  },
+  propsData: {
+    msg: "Hello"
+  },
+  computed: {
+    aDouble(this: Component) {
+      return this.a * 2;
+    },
+    aPlus: {
+      get(this: Component) {
+        return this.a + 1;
+      },
+      set(this: Component, v: number) {
+        this.a = v - 1;
+      },
+      cache: false
+    }
+  },
+  methods: {
+    plus(this: Component) {
+      this.a++;
+    }
+  },
+  watch: {
+    'a': function(val: number, oldVal: number) {
+      console.log(`new: ${val}, old: ${oldVal}`);
+    },
+    'b': 'someMethod',
+    'c': {
+      handler(val: number, oldval: number) {},
+      deep: true
+    }
+  },
+  el: "#app",
+  template: "<div>{{ message }}</div>",
+  render(createElement) {
+    return createElement("div", {
+      attrs: {
+        id: "foo"
+      },
+      props: {
+        myProp: "bar"
+      },
+      domProps: {
+        innerHTML: "baz"
+      },
+      on: {
+        click: new Function
+      },
+      nativeOn: {
+        click: new Function
+      },
+      class: {
+        foo: true,
+        bar: false
+      },
+      style: {
+        color: 'red',
+        fontSize: '14px'
+      },
+      key: 'myKey',
+      ref: 'myRef'
+    }, [
+      createElement("div", {}, "message"),
+      "message",
+      [createElement("div", {}, "message")]
+    ]);
+  },
+  staticRenderFns: [],
+
+  beforeCreate() {},
+  created() {},
+  beforeDestroy() {},
+  destroyed() {},
+  beforeMount() {},
+  mounted() {},
+  beforeUpdate() {},
+  updated() {},
+
+  directives: {
+    a: {
+      bind() {},
+      update() {},
+      componentMounted() {},
+      unbind() {}
+    },
+    b(el, binding, vnode, oldVnode) {
+      el.textContent;
+
+      binding.name;
+      binding.value;
+      binding.oldValue;
+      binding.expression;
+      binding.arg;
+      binding.modifiers["modifier"];
+    }
+  },
+  components: {
+    a: Vue.component(""),
+    b: {} as ComponentOptions
+  },
+  transitions: {},
+  filters: {
+    double(value: number) {
+      return value * 2;
+    }
+  },
+  parent: new Vue,
+  mixins: [Vue.component(""), ({} as ComponentOptions)],
+  name: "Component",
+  extends: {} as ComponentOptions,
+  delimiters: ["${", "}"]
+}

+ 19 - 0
types/test/plugin-test.ts

@@ -0,0 +1,19 @@
+import { Vue } from "../vue.d";
+import { PluginFunction, PluginObject } from "../plugin.d";
+
+class Option {
+  prefix: string;
+  suffix: string;
+}
+
+const plugin: PluginObject<Option> = {
+  install(Vue, option) {
+    if (typeof option !== "undefined") {
+      const {prefix, suffix} = option;
+    }
+  }
+}
+const installer: PluginFunction<Option> = function(Vue, option) { }
+
+Vue.use(plugin, new Option);
+Vue.use(installer, new Option);

+ 20 - 0
types/test/tsconfig.json

@@ -0,0 +1,20 @@
+{
+  "compilerOptions": {
+    "target": "es5",
+    "module": "commonjs",
+    "noImplicitAny": true,
+    "strictNullChecks": true,
+    "noEmit": true
+  },
+  "files": [
+    "../index.d.ts",
+    "../options.d.ts",
+    "../plugin.d.ts",
+    "../vnode.d.ts",
+    "../vue.d.ts",
+    "options-test.ts",
+    "plugin-test.ts",
+    "vue-test.ts"
+  ],
+  "compileOnSave": false
+}

+ 70 - 0
types/test/vue-test.ts

@@ -0,0 +1,70 @@
+import { Vue } from "../vue.d";
+
+class Test extends Vue {
+  testProperties() {
+    this.$data;
+    this.$el;
+    this.$options;
+    this.$parent;
+    this.$root;
+    this.$children;
+    this.$refs;
+    this.$slots;
+    this.$isServer;
+  }
+
+  testMethods() {
+    this.$mount("#app", false);
+    this.$forceUpdate();
+    this.$destroy();
+    this.$set({}, "key", "value");
+    this.$delete({}, "key");
+    this.$watch("a", (val: number, oldVal: number) => {}, {
+      immediate: true,
+      deep: false
+    })();
+    this.$watch(() => {}, (val: number) => {});
+    this.$on("", () => {});
+    this.$once("", () => {});
+    this.$off("", () => {});
+    this.$emit("", 1, 2, 3);
+    this.$nextTick(function() {
+      this.$nextTick;
+    });
+    this.$createElement("div", {}, "message", "");
+  }
+
+  static testConfig() {
+    const { config } = this;
+    config.silent;
+    config.optionMergeStrategies;
+    config.devtools;
+    config.errorHandler = (err, vm) => {
+      if (vm instanceof Test) {
+        vm.testProperties();
+        vm.testMethods();
+      }
+    };
+    config.keyCodes = { esc: 27 };
+  }
+
+  static testMethods() {
+    this.extend({
+      data() {
+        return {
+          msg: ""
+        };
+      }
+    });
+    this.nextTick(() => {});
+    this.set({}, "", "");
+    this.set([true, false, true], 1, true);
+    this.delete({}, "");
+    this.directive("", {bind() {}});
+    this.filter("", (value: number) => value);
+    this.component("", { data: () => ({}) });
+    this.use;
+    this.mixin(Test);
+    this.compile("<div>{{ message }}</div>");
+  }
+}

+ 4 - 0
types/typings.json

@@ -0,0 +1,4 @@
+{
+  "name": "vue",
+  "main": "index.d.ts"
+}

+ 65 - 0
types/vnode.d.ts

@@ -0,0 +1,65 @@
+import { Vue } from "./vue.d";
+
+export type VNodeChildren = VNodeChildrenArrayContents | string;
+export interface VNodeChildrenArrayContents {
+  [x: number]: VNode | string | VNodeChildren;
+}
+
+export interface VNode {
+  tag?: string;
+  data?: VNodeData;
+  children?: VNode[];
+  text?: string;
+  elm?: Node;
+  ns?: string;
+  context?: Vue;
+  key?: string | number;
+  componentOptions?: VNodeComponentOptions;
+  child?: Vue;
+  parent?: VNode;
+  raw?: boolean;
+  isStatic?: boolean;
+  isRootInsert: boolean;
+  isComment: boolean;
+}
+
+export interface VNodeComponentOptions {
+  Ctor: Vue;
+  propsData?: Object;
+  listeners?: Object;
+  children?: VNodeChildren;
+  tag?: string;
+}
+
+export interface VNodeData {
+  key?: string | number;
+  slot?: string;
+  ref?: string;
+  tag?: string;
+  staticClass?: string;
+  class?: any;
+  style?: Object[] | Object;
+  props?: { [key: string]: any };
+  attrs?: { [key: string]: any };
+  domProps?: { [key: string]: any };
+  hook?: { [key: string]: Function };
+  on?: { [key: string]: Function | Function[] };
+  nativeOn?: { [key: string]: Function | Function[] };
+  transition?: Object;
+  show?: boolean;
+  inlineTemplate?: {
+    render: Function;
+    staticRenderFns: Function[];
+  };
+  directives?: VNodeDirective[];
+  keepAlive?: boolean;
+}
+
+export interface VNodeDirective {
+  readonly name: string;
+  readonly value: any;
+  readonly oldValue: any;
+  readonly expression: any;
+  readonly arg: string;
+  readonly modifiers: { [key: string]: boolean };
+}

+ 69 - 0
types/vue.d.ts

@@ -0,0 +1,69 @@
+import {
+  ComponentOptions,
+  WatchOptions,
+  WatchHandler,
+  DirectiveOptions,
+  DirectiveFunction
+} from "./options.d";
+import { VNode, VNodeData, VNodeChildren } from "./vnode.d";
+import { PluginFunction, PluginObject } from "./plugin.d";
+
+export declare class Vue {
+
+  constructor(options?: ComponentOptions);
+
+  $data: Object;
+  readonly $el: HTMLElement;
+  readonly $options: ComponentOptions;
+  readonly $parent: Vue;
+  readonly $root: Vue;
+  readonly $children: Vue[];
+  readonly $refs: { [key: string]: Vue };
+  readonly $slots: { [key: string]: VNode[] };
+  readonly $isServer: boolean;
+
+  $mount(elementOrSelector?: Element | String, hydrating?: boolean): this;
+  $forceUpdate(): void;
+  $destroy(): void;
+  $set: typeof Vue.set;
+  $delete: typeof Vue.delete;
+  $watch(
+    expOrFn: string | Function,
+    callback: WatchHandler,
+    options?: WatchOptions
+  ): (() => void);
+  $on(event: string, callback: Function): this;
+  $once(event: string, callback: Function): this;
+  $off(event?: string, callback?: Function): this;
+  $emit(event: string, ...args: any[]): this;
+  $nextTick(callback?: (this: this) => void): void;
+  $createElement(
+    tag?: string | Vue,
+    data?: VNodeData,
+    children?: VNodeChildren,
+    namespace?: string
+  ): VNode;
+
+
+  static config: {
+    silent: boolean;
+    optionMergeStrategies: any;
+    devtools: boolean;
+    errorHandler(err: Error, vm: Vue): void;
+    keyCodes: { [key: string]: number };
+  }
+
+  static extend(options: ComponentOptions): Vue;
+  static nextTick(callback: () => void, context?: any[]): 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;
+
+  static directive(id: string, definition?: DirectiveOptions | DirectiveFunction): DirectiveOptions;
+  static filter(id: string, definition?: Function): Function;
+  static component(id: string, definition?: ComponentOptions | typeof Vue): typeof Vue;
+
+  static use<T>(plugin: PluginObject<T> | PluginFunction<T>, options?: T): void;
+  static mixin(mixin: typeof Vue | ComponentOptions): void;
+  static compile(template: string): { render: Function, staticRenderFns: Function };
+}