-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
Add typescript definition #3509
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
Changes from 7 commits
794ee6b
81ccc22
58cc89a
9566257
0a1f118
3a3b065
8df7277
ffb0cdf
fab7f11
1450ac7
da261d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import {Vue} from "./vue.d"; | ||
export = Vue; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
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)[]; | ||
|
||
init?(): void; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems |
||
created?(): 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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ComputedOptions may have |
||
} | ||
|
||
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; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { Vue as _Vue } from "./vue.d"; | ||
|
||
export interface PluginFunction<T> { | ||
(Vue: typeof _Vue, options?: T): void; | ||
} | ||
|
||
export interface PluginObject<T> { | ||
install: PluginFunction<T>; | ||
[key: string]: any; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
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; | ||
} | ||
} | ||
}, | ||
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", {}, this.message); | ||
}, | ||
staticRenderFns: [], | ||
|
||
init() {}, | ||
created() {}, | ||
beforeMount() {}, | ||
mounted() {}, | ||
beforeUpdate() {}, | ||
updated() {}, | ||
|
||
directives: { | ||
a: { | ||
bind() {}, | ||
update() {}, | ||
componentMounted() {}, | ||
unbind() {} | ||
}, | ||
b(el, binding, vnode, oldVnode) { | ||
el.textContent; | ||
} | ||
}, | ||
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: ["${", "}"] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"compilerOptions": { | ||
"target": "es5", | ||
"module": "commonjs", | ||
"noImplicitAny": true, | ||
"strictNullChecks": 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 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
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.delete({}, ""); | ||
this.directive("", {bind() {}}); | ||
this.filter("", (value: number) => value); | ||
this.component("", { data: () => ({}) }); | ||
this.use; | ||
this.mixin(Test); | ||
this.compile("<div>{{ message }}</div>"); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"name": "vue", | ||
"main": "index.d.ts" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
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; | ||
transitionInjected?: boolean; | ||
show?: boolean; | ||
inlineTemplate?: { | ||
render: Function; | ||
staticRenderFns: Function[]; | ||
}; | ||
directives?: VNodeDirective[]; | ||
keepAlive?: boolean; | ||
} | ||
|
||
export interface VNodeDirective { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I might be wrong, but is it desirable to mark |
||
name: string; | ||
value: any; | ||
oldValue: any; | ||
expression: any; | ||
arg: string; | ||
modifiers: { [key: string]: boolean }; | ||
} |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a union type is suitable for ComponentOptions? One for functional component and another for normal components.
Also
render
can be even more strict if it is typed likerender(this: never, createElement: typeof Vue.prototype.$createElement, content: ContextObject)
. So users cannot accessthis
in functional components.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's nice to make like
FunctionalComponentOptions
. This interface will tell us what properties are available / disable for functional components (Probably, lifecycle hooks anddata
are not available).