types: types for setup() + format types

This commit is contained in:
Evan You 2022-05-27 17:26:55 +08:00
parent f29ad1def5
commit 93214586aa
15 changed files with 1089 additions and 676 deletions

22
types/index.d.ts vendored
View File

@ -1,12 +1,9 @@
import { Vue } from "./vue"; import { Vue } from './vue'
import "./umd"; import './umd'
export default Vue; export default Vue
export { export { CreateElement, VueConstructor } from './vue'
CreateElement,
VueConstructor
} from "./vue";
export { export {
Component, Component,
@ -22,12 +19,9 @@ export {
WatchOptionsWithHandler, WatchOptionsWithHandler,
DirectiveFunction, DirectiveFunction,
DirectiveOptions DirectiveOptions
} from "./options"; } from './options'
export { export { PluginFunction, PluginObject } from './plugin'
PluginFunction,
PluginObject
} from "./plugin";
export { export {
VNodeChildren, VNodeChildren,
@ -36,4 +30,6 @@ export {
VNodeComponentOptions, VNodeComponentOptions,
VNodeData, VNodeData,
VNodeDirective VNodeDirective
} from "./vnode"; } from './vnode'
export { h, getCurrentInstance } from './v3'

349
types/options.d.ts vendored
View File

@ -1,37 +1,73 @@
import { Vue, CreateElement, CombinedVueInstance } from "./vue"; import { Vue, CreateElement, CombinedVueInstance } from './vue'
import { VNode, VNodeData, VNodeDirective, NormalizedScopedSlot } from "./vnode"; import { VNode, VNodeData, VNodeDirective, NormalizedScopedSlot } from './vnode'
import { SetupContext } from './v3'
type Constructor = { type Constructor = {
new (...args: any[]): any; new (...args: any[]): any
} }
// we don't support infer props in async component // we don't support infer props in async component
// N.B. ComponentOptions<V> is contravariant, the default generic should be bottom type // N.B. ComponentOptions<V> is contravariant, the default generic should be bottom type
export type Component<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = export type Component<
Data = DefaultData<never>,
Methods = DefaultMethods<never>,
Computed = DefaultComputed,
Props = DefaultProps,
SetupBindings = {}
> =
| typeof Vue | typeof Vue
| FunctionalComponentOptions<Props> | FunctionalComponentOptions<Props>
| ComponentOptions<never, Data, Methods, Computed, Props> | ComponentOptions<never, Data, Methods, Computed, Props, SetupBindings>
type EsModule<T> = T | { default: T } type EsModule<T> = T | { default: T }
type ImportedComponent<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> type ImportedComponent<
= EsModule<Component<Data, Methods, Computed, Props>> Data = DefaultData<never>,
Methods = DefaultMethods<never>,
Computed = DefaultComputed,
Props = DefaultProps,
SetupBindings = {}
> = EsModule<Component<Data, Methods, Computed, Props, SetupBindings>>
export type AsyncComponent<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> export type AsyncComponent<
= AsyncComponentPromise<Data, Methods, Computed, Props> Data = DefaultData<never>,
| AsyncComponentFactory<Data, Methods, Computed, Props> Methods = DefaultMethods<never>,
Computed = DefaultComputed,
Props = DefaultProps,
SetupBindings = {}
> =
| AsyncComponentPromise<Data, Methods, Computed, Props, SetupBindings>
| AsyncComponentFactory<Data, Methods, Computed, Props, SetupBindings>
export type AsyncComponentPromise<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = ( export type AsyncComponentPromise<
resolve: (component: Component<Data, Methods, Computed, Props>) => void, Data = DefaultData<never>,
Methods = DefaultMethods<never>,
Computed = DefaultComputed,
Props = DefaultProps,
SetupBindings = {}
> = (
resolve: (
component: Component<Data, Methods, Computed, Props, SetupBindings>
) => void,
reject: (reason?: any) => void reject: (reason?: any) => void
) => Promise<ImportedComponent<Data, Methods, Computed, Props>> | void; ) => Promise<
ImportedComponent<Data, Methods, Computed, Props, SetupBindings>
> | void
export type AsyncComponentFactory<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = () => { export type AsyncComponentFactory<
component: Promise<ImportedComponent<Data, Methods, Computed, Props>>; Data = DefaultData<never>,
loading?: ImportedComponent; Methods = DefaultMethods<never>,
error?: ImportedComponent; Computed = DefaultComputed,
delay?: number; Props = DefaultProps,
timeout?: number; SetupBindings = {}
> = () => {
component: Promise<
ImportedComponent<Data, Methods, Computed, Props, SetupBindings>
>
loading?: ImportedComponent
error?: ImportedComponent
delay?: number
timeout?: number
} }
/** /**
@ -48,141 +84,212 @@ type DataDef<Data, Props, V> = Data | ((this: Readonly<Props> & V) => Data)
/** /**
* This type should be used when an array of strings is used for a component's `props` value. * 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> = export type ThisTypedComponentOptionsWithArrayProps<
object & V extends Vue,
ComponentOptions<V, DataDef<Data, Record<PropNames, any>, V>, Methods, Computed, PropNames[], Record<PropNames, any>> & Data,
ThisType<CombinedVueInstance<V, Data, Methods, Computed, Readonly<Record<PropNames, any>>>>; Methods,
Computed,
PropNames extends string,
SetupBindings
> = object &
ComponentOptions<
V,
DataDef<Data, Record<PropNames, any>, V>,
Methods,
Computed,
PropNames[],
Record<PropNames, any>,
SetupBindings
> &
ThisType<
CombinedVueInstance<
V,
Data,
Methods,
Computed,
Readonly<Record<PropNames, any>>,
SetupBindings
>
>
/** /**
* This type should be used when an object mapped to `PropOptions` is used for a component's `props` value. * 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> = export type ThisTypedComponentOptionsWithRecordProps<
object & V extends Vue,
ComponentOptions<V, DataDef<Data, Props, V>, Methods, Computed, RecordPropsDefinition<Props>, Props> & Data,
ThisType<CombinedVueInstance<V, Data, Methods, Computed, Readonly<Props>>>; Methods,
Computed,
Props,
SetupBindings
> = object &
ComponentOptions<
V,
DataDef<Data, Props, V>,
Methods,
Computed,
RecordPropsDefinition<Props>,
Props,
SetupBindings
> &
ThisType<
CombinedVueInstance<
V,
Data,
Methods,
Computed,
Readonly<Props>,
SetupBindings
>
>
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 }
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< export interface ComponentOptions<
V extends Vue, V extends Vue,
Data=DefaultData<V>, Data = DefaultData<V>,
Methods=DefaultMethods<V>, Methods = DefaultMethods<V>,
Computed=DefaultComputed, Computed = DefaultComputed,
PropsDef=PropsDefinition<DefaultProps>, PropsDef = PropsDefinition<DefaultProps>,
Props=DefaultProps> { Props = DefaultProps,
data?: Data; RawBindings = {}
props?: PropsDef; > {
propsData?: object; data?: Data
computed?: Accessors<Computed>; props?: PropsDef
methods?: Methods; propsData?: object
watch?: Record<string, WatchOptionsWithHandler<any> | WatchHandler<any>>; computed?: Accessors<Computed>
methods?: Methods
watch?: Record<string, WatchOptionsWithHandler<any> | WatchHandler<any>>
el?: Element | string; setup?: (
template?: string; this: void,
props: Props,
ctx: SetupContext
) => Promise<RawBindings> | RawBindings | ((h: CreateElement) => VNode) | void
el?: Element | string
template?: string
// hack is for functional component type inference, should not be used in user code // hack is for functional component type inference, should not be used in user code
render?(createElement: CreateElement, hack: RenderContext<Props>): VNode; render?(createElement: CreateElement, hack: RenderContext<Props>): VNode
renderError?(createElement: CreateElement, err: Error): VNode; renderError?(createElement: CreateElement, err: Error): VNode
staticRenderFns?: ((createElement: CreateElement) => VNode)[]; staticRenderFns?: ((createElement: CreateElement) => VNode)[]
beforeCreate?(this: V): void; beforeCreate?(this: V): void
created?(): void; created?(): void
beforeDestroy?(): void; beforeDestroy?(): void
destroyed?(): void; destroyed?(): void
beforeMount?(): void; beforeMount?(): void
mounted?(): void; mounted?(): void
beforeUpdate?(): void; beforeUpdate?(): void
updated?(): void; updated?(): void
activated?(): void; activated?(): void
deactivated?(): void; deactivated?(): void
errorCaptured?(err: Error, vm: Vue, info: string): boolean | void; errorCaptured?(err: Error, vm: Vue, info: string): boolean | void
serverPrefetch?(this: V): Promise<void>; serverPrefetch?(this: V): Promise<void>
directives?: { [key: string]: DirectiveFunction | DirectiveOptions }; directives?: { [key: string]: DirectiveFunction | DirectiveOptions }
components?: { [key: string]: Component<any, any, any, any> | AsyncComponent<any, any, any, any> }; components?: {
transitions?: { [key: string]: object }; [key: string]:
filters?: { [key: string]: Function }; | Component<any, any, any, any>
| AsyncComponent<any, any, any, any>
}
transitions?: { [key: string]: object }
filters?: { [key: string]: Function }
provide?: object | (() => object); provide?: object | (() => object)
inject?: InjectOptions; inject?: InjectOptions
model?: { model?: {
prop?: string; prop?: string
event?: string; event?: string
}; }
parent?: Vue; parent?: Vue
mixins?: (ComponentOptions<Vue> | typeof Vue)[]; mixins?: (ComponentOptions<Vue> | typeof Vue)[]
name?: string; name?: string
// TODO: support properly inferred 'extends' // TODO: support properly inferred 'extends'
extends?: ComponentOptions<Vue> | typeof Vue; extends?: ComponentOptions<Vue> | typeof Vue
delimiters?: [string, string]; delimiters?: [string, string]
comments?: boolean; comments?: boolean
inheritAttrs?: boolean; inheritAttrs?: boolean
} }
export interface FunctionalComponentOptions<Props = DefaultProps, PropDefs = PropsDefinition<Props>> { export interface FunctionalComponentOptions<
name?: string; Props = DefaultProps,
props?: PropDefs; PropDefs = PropsDefinition<Props>
> {
name?: string
props?: PropDefs
model?: { model?: {
prop?: string; prop?: string
event?: string; event?: string
}; }
inject?: InjectOptions; inject?: InjectOptions
functional: boolean; functional: boolean
render?(this: undefined, createElement: CreateElement, context: RenderContext<Props>): VNode | VNode[]; render?(
this: undefined,
createElement: CreateElement,
context: RenderContext<Props>
): VNode | VNode[]
} }
export interface RenderContext<Props=DefaultProps> { export interface RenderContext<Props = DefaultProps> {
props: Props; props: Props
children: VNode[]; children: VNode[]
slots(): any; slots(): any
data: VNodeData; data: VNodeData
parent: Vue; parent: Vue
listeners: { [key: string]: Function | Function[] }; listeners: { [key: string]: Function | Function[] }
scopedSlots: { [key: string]: NormalizedScopedSlot }; scopedSlots: { [key: string]: NormalizedScopedSlot }
injections: any injections: any
} }
export type Prop<T> = { (): T } | { new(...args: never[]): T & object } | { new(...args: string[]): Function } export type Prop<T> =
| { (): T }
| { new (...args: never[]): T & object }
| { new (...args: string[]): Function }
export type PropType<T> = Prop<T> | Prop<T>[]; export type PropType<T> = Prop<T> | Prop<T>[]
export type PropValidator<T> = PropOptions<T> | PropType<T>; export type PropValidator<T> = PropOptions<T> | PropType<T>
export interface PropOptions<T=any> { export interface PropOptions<T = any> {
type?: PropType<T>; type?: PropType<T>
required?: boolean; required?: boolean
default?: T | null | undefined | (() => T | null | undefined); default?: T | null | undefined | (() => T | null | undefined)
validator?(value: T): boolean; validator?(value: T): boolean
} }
export type RecordPropsDefinition<T> = { export type RecordPropsDefinition<T> = {
[K in keyof T]: PropValidator<T[K]> [K in keyof T]: PropValidator<T[K]>
} }
export type ArrayPropsDefinition<T> = (keyof T)[]; export type ArrayPropsDefinition<T> = (keyof T)[]
export type PropsDefinition<T> = ArrayPropsDefinition<T> | RecordPropsDefinition<T>; export type PropsDefinition<T> =
| ArrayPropsDefinition<T>
| RecordPropsDefinition<T>
export interface ComputedOptions<T> { export interface ComputedOptions<T> {
get?(): T; get?(): T
set?(value: T): void; set?(value: T): void
cache?: boolean; cache?: boolean
} }
export type WatchHandler<T> = string | ((val: T, oldVal: T) => void); export type WatchHandler<T> = string | ((val: T, oldVal: T) => void)
export interface WatchOptions { export interface WatchOptions {
deep?: boolean; deep?: boolean
immediate?: boolean; immediate?: boolean
} }
export interface WatchOptionsWithHandler<T> extends WatchOptions { export interface WatchOptionsWithHandler<T> extends WatchOptions {
handler: WatchHandler<T>; handler: WatchHandler<T>
} }
export interface DirectiveBinding extends Readonly<VNodeDirective> { export interface DirectiveBinding extends Readonly<VNodeDirective> {
readonly modifiers: { [key: string]: boolean }; readonly modifiers: { [key: string]: boolean }
} }
export type DirectiveFunction = ( export type DirectiveFunction = (
@ -190,18 +297,20 @@ export type DirectiveFunction = (
binding: DirectiveBinding, binding: DirectiveBinding,
vnode: VNode, vnode: VNode,
oldVnode: VNode oldVnode: VNode
) => void; ) => void
export interface DirectiveOptions { export interface DirectiveOptions {
bind?: DirectiveFunction; bind?: DirectiveFunction
inserted?: DirectiveFunction; inserted?: DirectiveFunction
update?: DirectiveFunction; update?: DirectiveFunction
componentUpdated?: DirectiveFunction; componentUpdated?: DirectiveFunction
unbind?: DirectiveFunction; unbind?: DirectiveFunction
} }
export type InjectKey = string | symbol; export type InjectKey = string | symbol
export type InjectOptions = { export type InjectOptions =
[key: string]: InjectKey | { from?: InjectKey, default?: any } | {
} | string[]; [key: string]: InjectKey | { from?: InjectKey; default?: any }
}
| string[]

8
types/plugin.d.ts vendored
View File

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

View File

@ -1,8 +1,8 @@
import Vue, { AsyncComponent, Component } from "../index"; import Vue, { AsyncComponent, Component } from '../index'
const a: AsyncComponent = () => ({ const a: AsyncComponent = () => ({
component: new Promise<Component>((res, rej) => { component: new Promise<Component>((res, rej) => {
res({ template: "" }) res({ template: '' })
}) })
}) })
@ -10,14 +10,14 @@ const b: AsyncComponent = () => ({
// @ts-expect-error component has to be a Promise that resolves to a component // @ts-expect-error component has to be a Promise that resolves to a component
component: () => component: () =>
new Promise<Component>((res, rej) => { new Promise<Component>((res, rej) => {
res({ template: "" }) res({ template: '' })
}) })
}) })
const c: AsyncComponent = () => const c: AsyncComponent = () =>
new Promise<Component>((res, rej) => { new Promise<Component>((res, rej) => {
res({ res({
template: "" template: ''
}) })
}) })
@ -25,7 +25,7 @@ const d: AsyncComponent = () =>
new Promise<{ default: Component }>((res, rej) => { new Promise<{ default: Component }>((res, rej) => {
res({ res({
default: { default: {
template: "" template: ''
} }
}) })
}) })
@ -34,11 +34,11 @@ const e: AsyncComponent = () => ({
component: new Promise<{ default: Component }>((res, rej) => { component: new Promise<{ default: Component }>((res, rej) => {
res({ res({
default: { default: {
template: "" template: ''
} }
}) })
}) })
}) })
// Test that Vue.component accepts any AsyncComponent // Test that Vue.component accepts any AsyncComponent
Vue.component("async-compponent1", a) Vue.component('async-compponent1', a)

View File

@ -1,46 +1,46 @@
import Vue from "../index"; import Vue from '../index'
declare module "../vue" { declare module '../vue' {
// add instance property and method // add instance property and method
interface Vue { interface Vue {
$instanceProperty: string; $instanceProperty: string
$instanceMethod(): void; $instanceMethod(): void
} }
// add static property and method // add static property and method
interface VueConstructor { interface VueConstructor {
staticProperty: string; staticProperty: string
staticMethod(): void; staticMethod(): void
} }
} }
// augment ComponentOptions // augment ComponentOptions
declare module "../options" { declare module '../options' {
interface ComponentOptions<V extends Vue> { interface ComponentOptions<V extends Vue> {
foo?: string; foo?: string
} }
} }
const vm = new Vue({ const vm = new Vue({
props: ["bar"], props: ['bar'],
data: { data: {
a: true a: true
}, },
foo: "foo", foo: 'foo',
methods: { methods: {
foo() { foo() {
this.a = false; this.a = false
} }
}, },
computed: { computed: {
BAR(): string { BAR(): string {
return this.bar.toUpperCase(); return this.bar.toUpperCase()
} }
} }
}); })
vm.$instanceProperty; vm.$instanceProperty
vm.$instanceMethod(); vm.$instanceMethod()
Vue.staticProperty; Vue.staticProperty
Vue.staticMethod(); Vue.staticMethod()

View File

@ -1,9 +1,9 @@
import Vue, { PropType, VNode } from "../index"; import Vue, { PropType, VNode } from '../index'
import { ComponentOptions, Component } from "../index"; import { ComponentOptions, Component } from '../index'
import { CreateElement } from "../vue"; import { CreateElement } from '../vue'
interface MyComponent extends Vue { interface MyComponent extends Vue {
a: number; a: number
} }
const option: ComponentOptions<MyComponent> = { const option: ComponentOptions<MyComponent> = {
@ -20,10 +20,10 @@ const componentType: Component = option
Vue.component('sub-component', { Vue.component('sub-component', {
components: { components: {
a: Vue.component(""), a: Vue.component(''),
b: {} b: {}
} }
}); })
Vue.component('prop-component', { Vue.component('prop-component', {
props: { props: {
@ -31,7 +31,7 @@ Vue.component('prop-component', {
name: { name: {
type: String, type: String,
default: '0', default: '0',
required: true, required: true
} }
}, },
data() { data() {
@ -40,7 +40,7 @@ Vue.component('prop-component', {
capName: this.name.toUpperCase() capName: this.name.toUpperCase()
} }
} }
}); })
Vue.component('string-prop', { Vue.component('string-prop', {
props: ['size', 'name'], props: ['size', 'name'],
@ -50,7 +50,7 @@ Vue.component('string-prop', {
capName: this.name.isany capName: this.name.isany
} }
} }
}); })
class User { class User {
private u = 1 private u = 1
@ -60,15 +60,15 @@ class Cat {
} }
interface IUser { interface IUser {
foo: string, foo: string
bar: number bar: number
} }
interface ICat { interface ICat {
foo: any, foo: any
bar: object bar: object
} }
type ConfirmCallback = (confirm: boolean) => void; type ConfirmCallback = (confirm: boolean) => void
Vue.component('union-prop', { Vue.component('union-prop', {
props: { props: {
@ -79,16 +79,16 @@ Vue.component('union-prop', {
union: [User, Number] as PropType<User | number> union: [User, Number] as PropType<User | number>
}, },
data() { data() {
this.cat; this.cat
this.complexUnion; this.complexUnion
this.kittyUser; this.kittyUser
this.callback(true); this.callback(true)
this.union; this.union
return { return {
fixedSize: this.union, fixedSize: this.union
} }
} }
}); })
Vue.component('union-prop-with-no-casting', { Vue.component('union-prop-with-no-casting', {
props: { props: {
@ -98,10 +98,10 @@ Vue.component('union-prop-with-no-casting', {
regex: RegExp regex: RegExp
}, },
data() { data() {
this.mixed; this.mixed
this.object; this.object
this.primitive; this.primitive
this.regex.compile; this.regex.compile
} }
}) })
@ -113,9 +113,9 @@ Vue.component('prop-with-primitive-default', {
} }
}, },
created(): void { created(): void {
this.id; this.id
} }
}); })
Vue.component('component', { Vue.component('component', {
data() { data() {
@ -130,40 +130,40 @@ Vue.component('component', {
name: { name: {
type: String, type: String,
default: '0', default: '0',
required: true, required: true
} }
}, },
propsData: { propsData: {
msg: "Hello" msg: 'Hello'
}, },
computed: { computed: {
aDouble(): number { aDouble(): number {
return this.a * 2; return this.a * 2
}, },
aPlus: { aPlus: {
get(): number { get(): number {
return this.a + 1; return this.a + 1
}, },
set(v: number) { set(v: number) {
this.a = v - 1; this.a = v - 1
}, },
cache: false cache: false
} }
}, },
methods: { methods: {
plus(): void { plus(): void {
this.a++; this.a++
this.aDouble.toFixed(); this.aDouble.toFixed()
this.aPlus = 1; this.aPlus = 1
this.size.toFixed(); this.size.toFixed()
} }
}, },
watch: { watch: {
'a': function(val: number, oldVal: number) { a: function (val: number, oldVal: number) {
console.log(`new: ${val}, old: ${oldVal}`); console.log(`new: ${val}, old: ${oldVal}`)
}, },
'b': 'someMethod', b: 'someMethod',
'c': { c: {
handler(val, oldVal) { handler(val, oldVal) {
this.a = val this.a = val
}, },
@ -174,71 +174,77 @@ Vue.component('component', {
immediate: true immediate: true
} }
}, },
el: "#app", el: '#app',
template: "<div>{{ message }}</div>", template: '<div>{{ message }}</div>',
render(createElement) { render(createElement) {
return createElement("div", { return createElement(
attrs: { 'div',
id: "foo" {
attrs: {
id: 'foo'
},
props: {
myProp: 'bar'
},
directives: [
{
name: 'a',
value: 'foo'
}
],
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',
refInFor: true
}, },
props: { [
myProp: "bar" createElement(),
}, createElement('div', 'message'),
directives: [{ createElement(Vue.component('component')),
name: 'a', createElement({} as ComponentOptions<Vue>),
value: 'foo' createElement({
}], functional: true,
domProps: { render(c: CreateElement) {
innerHTML: "baz" return createElement()
}, }
on: { }),
click: new Function
},
nativeOn: {
click: new Function
},
class: {
foo: true,
bar: false
},
style: {
color: 'red',
fontSize: '14px'
},
key: 'myKey',
ref: 'myRef',
refInFor: true
}, [
createElement(),
createElement("div", "message"),
createElement(Vue.component("component")),
createElement({} as ComponentOptions<Vue>),
createElement({
functional: true,
render(c: CreateElement) {
return createElement()
}
}),
createElement(() => Vue.component("component")), createElement(() => Vue.component('component')),
createElement(() => ( {} as ComponentOptions<Vue> )), createElement(() => ({} as ComponentOptions<Vue>)),
createElement((resolve, reject) => { createElement((resolve, reject) => {
resolve({} as ComponentOptions<Vue>); resolve({} as ComponentOptions<Vue>)
reject(); reject()
}), }),
"message", 'message',
[createElement("div", "message")] [createElement('div', 'message')]
]); ]
)
}, },
renderError(createElement, err) { renderError(createElement, err) {
return createElement('pre', { style: { color: 'red' }}, err.stack) return createElement('pre', { style: { color: 'red' } }, err.stack)
}, },
staticRenderFns: [], staticRenderFns: [],
beforeCreate() { beforeCreate() {
(this as any).a = 1; ;(this as any).a = 1
}, },
created() {}, created() {},
beforeDestroy() {}, beforeDestroy() {},
@ -255,7 +261,7 @@ Vue.component('component', {
info.toUpperCase() info.toUpperCase()
return true return true
}, },
serverPrefetch () { serverPrefetch() {
return Promise.resolve() return Promise.resolve()
}, },
@ -268,44 +274,43 @@ Vue.component('component', {
unbind() {} unbind() {}
}, },
b(el, binding, vnode, oldVnode) { b(el, binding, vnode, oldVnode) {
el.textContent; el.textContent
binding.name; binding.name
binding.value; binding.value
binding.oldValue; binding.oldValue
binding.expression; binding.expression
binding.arg; binding.arg
binding.modifiers["modifier"]; binding.modifiers['modifier']
} }
}, },
components: { components: {
a: Vue.component(""), a: Vue.component(''),
b: {} as ComponentOptions<Vue> b: {} as ComponentOptions<Vue>
}, },
transitions: {}, transitions: {},
filters: { filters: {
double(value: number) { double(value: number) {
return value * 2; return value * 2
} }
}, },
parent: new Vue, parent: new Vue(),
mixins: [Vue.component(""), ({} as ComponentOptions<Vue>)], mixins: [Vue.component(''), {} as ComponentOptions<Vue>],
name: "Component", name: 'Component',
extends: {} as ComponentOptions<Vue>, extends: {} as ComponentOptions<Vue>,
delimiters: ["${", "}"] delimiters: ['${', '}']
}); })
Vue.component('custom-prop-type-function', { Vue.component('custom-prop-type-function', {
props: { props: {
callback: Function as PropType<(confirm: boolean) => void>, callback: Function as PropType<(confirm: boolean) => void>
}, },
methods: { methods: {
confirm(){ confirm() {
this.callback(true); this.callback(true)
} }
} }
}); })
Vue.component('provide-inject', { Vue.component('provide-inject', {
provide: { provide: {
@ -316,7 +321,7 @@ Vue.component('provide-inject', {
injectBar: Symbol(), injectBar: Symbol(),
injectBaz: { from: 'baz' }, injectBaz: { from: 'baz' },
injectQux: { default: 1 }, injectQux: { default: 1 },
injectQuux: { from: 'quuz', default: () => ({ value: 1 })} injectQuux: { from: 'quuz', default: () => ({ value: 1 }) }
} }
}) })
@ -327,13 +332,13 @@ Vue.component('provide-function', {
}) })
Vue.component('component-with-slot', { Vue.component('component-with-slot', {
render (h): VNode { render(h): VNode {
return h('div', this.$slots.default) return h('div', this.$slots.default)
} }
}) })
Vue.component('component-with-scoped-slot', { Vue.component('component-with-scoped-slot', {
render (h) { render(h) {
interface ScopedSlotProps { interface ScopedSlotProps {
msg: string msg: string
} }
@ -367,11 +372,12 @@ Vue.component('component-with-scoped-slot', {
}, },
components: { components: {
child: { child: {
render (this: Vue, h: CreateElement) { render(this: Vue, h: CreateElement) {
const defaultSlot = this.$scopedSlots['default']!({ msg: 'hi' }) const defaultSlot = this.$scopedSlots['default']!({ msg: 'hi' })
defaultSlot && defaultSlot.forEach(vnode => { defaultSlot &&
vnode.tag defaultSlot.forEach(vnode => {
}) vnode.tag
})
return h('div', [ return h('div', [
defaultSlot, defaultSlot,
this.$scopedSlots['item']!({ msg: 'hello' }) this.$scopedSlots['item']!({ msg: 'hello' })
@ -382,7 +388,7 @@ Vue.component('component-with-scoped-slot', {
}) })
Vue.component('narrow-array-of-vnode-type', { Vue.component('narrow-array-of-vnode-type', {
render (h): VNode { render(h): VNode {
const slot = this.$scopedSlots.default!({}) const slot = this.$scopedSlots.default!({})
if (typeof slot === 'string') { if (typeof slot === 'string') {
// <template slot-scope="data">bare string</template> // <template slot-scope="data">bare string</template>
@ -410,16 +416,16 @@ Vue.component('functional-component', {
functional: true, functional: true,
inject: ['foo'], inject: ['foo'],
render(createElement, context) { render(createElement, context) {
context.props; context.props
context.children; context.children
context.slots(); context.slots()
context.data; context.data
context.parent; context.parent
context.scopedSlots; context.scopedSlots
context.listeners.click; context.listeners.click
return createElement("div", {}, context.children); return createElement('div', {}, context.children)
} }
}); })
Vue.component('functional-component-object-inject', { Vue.component('functional-component-object-inject', {
functional: true, functional: true,
@ -428,7 +434,7 @@ Vue.component('functional-component-object-inject', {
bar: Symbol(), bar: Symbol(),
baz: { from: 'baz' }, baz: { from: 'baz' },
qux: { default: 1 }, qux: { default: 1 },
quux: { from: 'quuz', default: () => ({ value: 1 })} quux: { from: 'quuz', default: () => ({ value: 1 }) }
}, },
render(h) { render(h) {
return h('div') return h('div')
@ -443,23 +449,25 @@ Vue.component('functional-component-multi-root', {
functional: true, functional: true,
render(h) { render(h) {
return [ return [
h("tr", [h("td", "foo"), h("td", "bar")]), h('tr', [h('td', 'foo'), h('td', 'bar')]),
h("tr", [h("td", "lorem"), h("td", "ipsum")]) h('tr', [h('td', 'lorem'), h('td', 'ipsum')])
] ]
} }
}) })
Vue.component("async-component", ((resolve, reject) => { Vue.component('async-component', (resolve, reject) => {
setTimeout(() => { setTimeout(() => {
resolve(Vue.component("component")); resolve(Vue.component('component'))
}, 0); }, 0)
return new Promise((resolve) => { return new Promise(resolve => {
resolve({ resolve({
functional: true, functional: true,
render(h: CreateElement) { return h('div') } render(h: CreateElement) {
}); return h('div')
}
})
}) })
})); })
Vue.component('functional-component-v-model', { Vue.component('functional-component-v-model', {
props: ['foo'], props: ['foo'],
@ -469,33 +477,33 @@ Vue.component('functional-component-v-model', {
event: 'change' event: 'change'
}, },
render(createElement, context) { render(createElement, context) {
return createElement("input", { return createElement('input', {
on: { on: {
input: new Function() input: new Function()
}, },
domProps: { domProps: {
value: context.props.foo value: context.props.foo
} }
}); })
} }
}); })
Vue.component('async-es-module-component', () => import('./es-module')) Vue.component('async-es-module-component', () => import('./es-module'))
Vue.component('directive-expression-optional-string', { Vue.component('directive-expression-optional-string', {
render(createElement) { render(createElement) {
return createElement("div", { return createElement('div', {
directives: [ directives: [
{ {
name: 'has-expression', name: 'has-expression',
value: 2, value: 2,
expression: '1 + 1', expression: '1 + 1'
}, {
name: 'no-expression',
value: 'foo',
}, },
], {
name: 'no-expression',
value: 'foo'
}
]
}) })
} }
}); })

View File

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

35
types/test/setup-test.ts Normal file
View File

@ -0,0 +1,35 @@
import Vue from '../index'
// object props
Vue.extend({
props: {
foo: String,
bar: Number
},
setup(props) {
props.foo + 'foo'
props.bar + 123
}
})
// array props
Vue.extend({
props: ['foo', 'bar'],
setup(props) {
props.foo
props.bar
}
})
// context
Vue.extend({
setup(_props, ctx) {
if (ctx.attrs.id) {
}
ctx.emit('foo')
ctx.slots.default && ctx.slots.default()
ctx.expose({
foo: 123
})
}
})

View File

@ -1,119 +1,127 @@
import Vue, { VNode, VNodeDirective } from '../index'; import Vue, { VNode, VNodeDirective } from '../index'
import VueSSRClientPlugin = require('../../packages/vue-server-renderer/client-plugin'); import VueSSRClientPlugin = require('../../packages/vue-server-renderer/client-plugin')
import VueSSRServerPlugin = require('../../packages/vue-server-renderer/server-plugin'); import VueSSRServerPlugin = require('../../packages/vue-server-renderer/server-plugin')
import webpack = require('webpack'); import webpack = require('webpack')
import { readFileSync } from 'fs'; import { readFileSync } from 'fs'
import { createRenderer, createBundleRenderer } from '../../packages/vue-server-renderer'; import {
createRenderer,
createBundleRenderer
} from '../../packages/vue-server-renderer'
function createApp (context: any) { function createApp(context: any) {
return new Vue({ return new Vue({
data: { data: {
url: context.url url: context.url
}, },
template: `<div>The visited URL is: {{ url }}</div>` template: `<div>The visited URL is: {{ url }}</div>`
}); })
} }
// Renderer test // Renderer test
const app = createApp({ url: 'http://localhost:8000/' }); const app = createApp({ url: 'http://localhost:8000/' })
const renderer = createRenderer({ const renderer = createRenderer({
template: readFileSync('./index.template.html', 'utf-8') template: readFileSync('./index.template.html', 'utf-8')
}); })
const context = { const context = {
title: 'Hello', title: 'Hello',
meta: ` meta: `
<meta name="description" content="Vue.js SSR Example"> <meta name="description" content="Vue.js SSR Example">
` `
}; }
renderer.renderToString(app, (err, html) => { renderer.renderToString(app, (err, html) => {
if (err) throw err; if (err) throw err
const res: string = html; const res: string = html
}); })
renderer.renderToString(app, context, (err, html) => { renderer.renderToString(app, context, (err, html) => {
if (err) throw err; if (err) throw err
const res: string = html; const res: string = html
}); })
renderer.renderToString(app) renderer
.renderToString(app)
.then(html => { .then(html => {
const res: string = html; const res: string = html
}) })
.catch(err => { .catch(err => {
throw err; throw err
}); })
renderer.renderToString(app, context) renderer
.renderToString(app, context)
.then(html => { .then(html => {
const res: string = html; const res: string = html
}) })
.catch(err => { .catch(err => {
throw err; throw err
}); })
renderer.renderToStream(app, context).on('data', chunk => { renderer.renderToStream(app, context).on('data', chunk => {
const html = chunk.toString(); const html = chunk.toString()
}); })
// Bundle renderer test // Bundle renderer test
declare const cacheClient: { [key: string]: string }; declare const cacheClient: { [key: string]: string }
const bundleRenderer = createBundleRenderer('/path/to/vue-ssr-server-bundle.json', { const bundleRenderer = createBundleRenderer(
inject: false, '/path/to/vue-ssr-server-bundle.json',
runInNewContext: 'once', {
basedir: '/path/to/base', inject: false,
runInNewContext: 'once',
basedir: '/path/to/base',
shouldPreload: (file, type) => { shouldPreload: (file, type) => {
if (type === 'script' || type === 'style') { if (type === 'script' || type === 'style') {
return true; return true
} }
if (type === 'font') { if (type === 'font') {
return /\.woff2$/.test(file); return /\.woff2$/.test(file)
} }
if (type === 'image') { if (type === 'image') {
return file === 'hero.jpg'; return file === 'hero.jpg'
} }
return false; return false
},
cache: {
get: key => {
return cacheClient[key];
}, },
set: (key, val) => {
cacheClient[key] = val;
},
has: key => {
return !!cacheClient[key];
}
},
directives: { cache: {
example (vnode: VNode, directiveMeta: VNodeDirective) { get: key => {
// transform vnode based on directive binding metadata return cacheClient[key]
},
set: (key, val) => {
cacheClient[key] = val
},
has: key => {
return !!cacheClient[key]
}
},
directives: {
example(vnode: VNode, directiveMeta: VNodeDirective) {
// transform vnode based on directive binding metadata
}
} }
} }
}); )
bundleRenderer.renderToString(context, (err, html) => { bundleRenderer.renderToString(context, (err, html) => {
if (err) throw err; if (err) throw err
const res: string = html; const res: string = html
}); })
bundleRenderer.renderToString().then(html => { bundleRenderer.renderToString().then(html => {
const res: string = html; const res: string = html
}); })
bundleRenderer.renderToString(context).then(html => { bundleRenderer.renderToString(context).then(html => {
const res: string = html; const res: string = html
}); })
bundleRenderer.renderToStream(context).on('data', chunk => { bundleRenderer.renderToStream(context).on('data', chunk => {
const html = chunk.toString(); const html = chunk.toString()
}); })
// webpack plugins // webpack plugins
webpack({ webpack({
@ -125,4 +133,4 @@ webpack({
filename: 'server-bundle.json' filename: 'server-bundle.json'
}) })
] ]
}); })

View File

@ -1,7 +1,7 @@
const vm = new Vue({ const vm = new Vue({
template: "<div>hi</div>" template: '<div>hi</div>'
}); })
const options: Vue.ComponentOptions<Vue> = { const options: Vue.ComponentOptions<Vue> = {
template: "<div>test</div>" template: '<div>test</div>'
}; }

View File

@ -1,79 +1,82 @@
import Vue, { VNode } from "../index"; import Vue, { VNode } from '../index'
import { ComponentOptions } from "../options"; import { ComponentOptions } from '../options'
class Test extends Vue { class Test extends Vue {
a: number = 0; a: number = 0
testProperties() { testProperties() {
this.$data; this.$data
this.$el; this.$el
this.$options; this.$options
this.$parent; this.$parent
this.$root; this.$root
this.$children; this.$children
this.$refs; this.$refs
this.$slots; this.$slots
this.$isServer; this.$isServer
this.$ssrContext; this.$ssrContext
this.$vnode; this.$vnode
} }
// test property reification // test property reification
$el!: HTMLElement | SVGElement; $el!: HTMLElement | SVGElement
$refs!: { $refs!: {
vue: Vue, vue: Vue
element: HTMLInputElement, element: HTMLInputElement
vues: Vue[], vues: Vue[]
elements: HTMLInputElement[] elements: HTMLInputElement[]
} }
testReification() { testReification() {
this.$refs.vue.$data; this.$refs.vue.$data
this.$refs.element.value; this.$refs.element.value
this.$refs.vues[0].$data; this.$refs.vues[0].$data
this.$refs.elements[0].value; this.$refs.elements[0].value
} }
testMethods() { testMethods() {
this.$mount("#app", false); this.$mount('#app', false)
this.$forceUpdate(); this.$forceUpdate()
this.$destroy(); this.$destroy()
this.$set({}, "key", "value"); this.$set({}, 'key', 'value')
this.$delete({}, "key"); this.$delete({}, 'key')
this.$watch("a", (val: number, oldVal: number) => {}, { this.$watch('a', (val: number, oldVal: number) => {}, {
immediate: true, immediate: true,
deep: false deep: false
})(); })()
this.$watch(() => this.a, (val: number) => {}); this.$watch(
this.$on("", () => {}); () => this.a,
this.$once("", () => {}); (val: number) => {}
this.$off("", () => {}); )
this.$emit("", 1, 2, 3); this.$on('', () => {})
this.$nextTick(function() { this.$once('', () => {})
this.$nextTick; this.$off('', () => {})
}); this.$emit('', 1, 2, 3)
this.$nextTick().then(() => {}); this.$nextTick(function () {
this.$createElement("div", {}, "message"); this.$nextTick
})
this.$nextTick().then(() => {})
this.$createElement('div', {}, 'message')
} }
static testConfig() { static testConfig() {
const { config } = this; const { config } = this
config.silent; config.silent
config.optionMergeStrategies; config.optionMergeStrategies
config.devtools; config.devtools
config.errorHandler = (err, vm) => { config.errorHandler = (err, vm) => {
if (vm instanceof Test) { if (vm instanceof Test) {
vm.testProperties(); vm.testProperties()
vm.testMethods(); vm.testMethods()
} }
}; }
config.warnHandler = (msg, vm) => { config.warnHandler = (msg, vm) => {
if (vm instanceof Test) { if (vm instanceof Test) {
vm.testProperties(); vm.testProperties()
vm.testMethods(); vm.testMethods()
} }
}; }
config.keyCodes = { esc: 27 }; config.keyCodes = { esc: 27 }
config.ignoredElements = ['foo', /^ion-/]; config.ignoredElements = ['foo', /^ion-/]
config.async = false config.async = false
} }
@ -81,108 +84,114 @@ class Test extends Vue {
this.extend({ this.extend({
data() { data() {
return { return {
msg: "" msg: ''
}; }
} }
}); })
this.nextTick(() => {}); this.nextTick(() => {})
this.nextTick(function () { this.nextTick(
console.log(this.text === 'test'); function () {
}, { text: 'test'}); console.log(this.text === 'test')
this.nextTick().then(() => {}); },
this.set({}, "", ""); { text: 'test' }
this.set({}, 1, ""); )
this.set([true, false, true], 1, true); this.nextTick().then(() => {})
this.delete({}, ""); this.set({}, '', '')
this.delete({}, 1); this.set({}, 1, '')
this.delete([true, false], 0); this.set([true, false, true], 1, true)
this.directive("", {bind() {}}); this.delete({}, '')
this.filter("", (value: number) => value); this.delete({}, 1)
this.component("", { data: () => ({}) }); this.delete([true, false], 0)
this.component("", { functional: true, render(h) { return h("div", "hello!") } }); this.directive('', { bind() {} })
this.use; this.filter('', (value: number) => value)
this.mixin(Test); this.component('', { data: () => ({}) })
this.compile("<div>{{ message }}</div>"); this.component('', {
this functional: true,
.use(() => { render(h) {
return h('div', 'hello!')
}) }
.use(() => { })
this.use
}) this.mixin(Test)
this.compile('<div>{{ message }}</div>')
this.use(() => {})
.use(() => {})
.mixin({})
.mixin({}) .mixin({})
.mixin({});
} }
} }
const HelloWorldComponent = Vue.extend({ const HelloWorldComponent = Vue.extend({
props: ["name"], props: ['name'],
data() { data() {
return { return {
message: "Hello " + this.name, message: 'Hello ' + this.name
} }
}, },
computed: { computed: {
shouted(): string { shouted(): string {
return this.message.toUpperCase(); return this.message.toUpperCase()
} }
}, },
methods: { methods: {
getMoreExcited() { getMoreExcited() {
this.message += "!"; this.message += '!'
} }
}, },
watch: { watch: {
message(a: string) { message(a: string) {
console.log(`Message ${this.message} was changed!`); console.log(`Message ${this.message} was changed!`)
} }
} }
}); })
const FunctionalHelloWorldComponent = Vue.extend({ const FunctionalHelloWorldComponent = Vue.extend({
functional: true, functional: true,
props: ["name"], props: ['name'],
render(createElement, ctxt) { render(createElement, ctxt) {
return createElement("div", "Hello " + ctxt.props.name) return createElement('div', 'Hello ' + ctxt.props.name)
} }
}); })
const FunctionalScopedSlotsComponent = Vue.extend({ const FunctionalScopedSlotsComponent = Vue.extend({
functional: true, functional: true,
render(h, ctx) { render(h, ctx) {
return ctx.scopedSlots.default && ctx.scopedSlots.default({}) || h('div', 'functional scoped slots'); return (
(ctx.scopedSlots.default && ctx.scopedSlots.default({})) ||
h('div', 'functional scoped slots')
)
} }
}); })
const Parent = Vue.extend({ const Parent = Vue.extend({
data() { data() {
return { greeting: 'Hello' } return { greeting: 'Hello' }
} }
}); })
const Child = Parent.extend({ const Child = Parent.extend({
methods: { methods: {
foo() { foo() {
console.log(this.greeting.toLowerCase()); console.log(this.greeting.toLowerCase())
} }
} }
}); })
const GrandChild = Child.extend({ const GrandChild = Child.extend({
computed: { computed: {
lower(): string { lower(): string {
return this.greeting.toLowerCase(); return this.greeting.toLowerCase()
} }
} }
}); })
new GrandChild().lower.toUpperCase(); new GrandChild().lower.toUpperCase()
for (let _ in (new Test()).$options) { for (let _ in new Test().$options) {
} }
declare const options: ComponentOptions<Vue>; declare const options: ComponentOptions<Vue>
Vue.extend(options); Vue.extend(options)
Vue.component('test-comp', options); Vue.component('test-comp', options)
new Vue(options); new Vue(options)
// cyclic example // cyclic example
Vue.extend({ Vue.extend({
@ -194,21 +203,21 @@ Vue.extend({
methods: { methods: {
foo() {} foo() {}
}, },
mounted () { mounted() {
this.foo() this.foo()
}, },
// manual annotation // manual annotation
render (h): VNode { render(h): VNode {
const a = this.bar const a = this.bar
return h('canvas', {}, [a]) return h('canvas', {}, [a])
} }
}) })
declare function decorate<VC extends typeof Vue>(v: VC): VC; declare function decorate<VC extends typeof Vue>(v: VC): VC
@decorate @decorate
class Decorated extends Vue { class Decorated extends Vue {
a = 123; a = 123
} }
const obj = Vue.observable({ a: 1 }) const obj = Vue.observable({ a: 1 })
@ -216,25 +225,23 @@ obj.a++
// VNodeData style tests. // VNodeData style tests.
const ComponentWithStyleInVNodeData = Vue.extend({ const ComponentWithStyleInVNodeData = Vue.extend({
render (h) { render(h) {
const elementWithStyleAsString = h('div', { const elementWithStyleAsString = h('div', {
style: 'background-color: red;' style: 'background-color: red;'
}); })
const elementWithStyleAsObject = h('div', { const elementWithStyleAsObject = h('div', {
style: { backgroundColor: 'green' } style: { backgroundColor: 'green' }
}); })
const elementWithStyleAsArrayOfObjects = h('div', { const elementWithStyleAsArrayOfObjects = h('div', {
style: [ style: [{ backgroundColor: 'blue' }]
{ backgroundColor: 'blue' } })
]
});
return h('div', undefined, [ return h('div', undefined, [
elementWithStyleAsString, elementWithStyleAsString,
elementWithStyleAsObject, elementWithStyleAsObject,
elementWithStyleAsArrayOfObjects elementWithStyleAsArrayOfObjects
]); ])
} }
}); })

74
types/umd.d.ts vendored
View File

@ -1,48 +1,68 @@
import * as V from "./index"; import * as V from './index'
import { import {
DefaultData, DefaultData,
DefaultProps, DefaultProps,
DefaultMethods, DefaultMethods,
DefaultComputed, DefaultComputed,
PropsDefinition PropsDefinition
} from "./options"; } from './options'
// Expose some types for backward compatibility... // Expose some types for backward compatibility...
declare namespace Vue { declare namespace Vue {
// vue.d.ts // vue.d.ts
export type CreateElement = V.CreateElement; export type CreateElement = V.CreateElement
export type VueConstructor<V extends Vue = Vue> = V.VueConstructor<V>; export type VueConstructor<V extends Vue = Vue> = V.VueConstructor<V>
// options.d.ts // options.d.ts
export type Component<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = V.Component<Data, Methods, Computed, Props>; export type Component<
export type AsyncComponent<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = V.AsyncComponent<Data, Methods, Computed, Props>; Data = DefaultData<never>,
export type ComponentOptions<V extends Vue, Data=DefaultData<V>, Methods=DefaultMethods<V>, Computed=DefaultComputed, PropsDef=PropsDefinition<DefaultProps>, Props=DefaultProps> = V.ComponentOptions<V, Data, Methods, Computed, PropsDef, Props>; Methods = DefaultMethods<never>,
export type FunctionalComponentOptions<Props = DefaultProps, PropDefs = PropsDefinition<Props>> = V.FunctionalComponentOptions<Props, PropDefs>; Computed = DefaultComputed,
export type RenderContext<Props=DefaultProps> = V.RenderContext<Props>; Props = DefaultProps
export type PropType<T> = V.PropType<T>; > = V.Component<Data, Methods, Computed, Props>
export type PropOptions<T=any> = V.PropOptions<T>; export type AsyncComponent<
export type ComputedOptions<T> = V.ComputedOptions<T>; Data = DefaultData<never>,
export type WatchHandler<T> = V.WatchHandler<T>; Methods = DefaultMethods<never>,
export type WatchOptions = V.WatchOptions; Computed = DefaultComputed,
export type WatchOptionsWithHandler<T> = V.WatchOptionsWithHandler<T>; Props = DefaultProps
export type DirectiveFunction = V.DirectiveFunction; > = V.AsyncComponent<Data, Methods, Computed, Props>
export type DirectiveOptions = V.DirectiveOptions; export type ComponentOptions<
V extends Vue,
Data = DefaultData<V>,
Methods = DefaultMethods<V>,
Computed = DefaultComputed,
PropsDef = PropsDefinition<DefaultProps>,
Props = DefaultProps
> = V.ComponentOptions<V, Data, Methods, Computed, PropsDef, Props>
export type FunctionalComponentOptions<
Props = DefaultProps,
PropDefs = PropsDefinition<Props>
> = V.FunctionalComponentOptions<Props, PropDefs>
export type RenderContext<Props = DefaultProps> = V.RenderContext<Props>
export type PropType<T> = V.PropType<T>
export type PropOptions<T = any> = V.PropOptions<T>
export type ComputedOptions<T> = V.ComputedOptions<T>
export type WatchHandler<T> = V.WatchHandler<T>
export type WatchOptions = V.WatchOptions
export type WatchOptionsWithHandler<T> = V.WatchOptionsWithHandler<T>
export type DirectiveFunction = V.DirectiveFunction
export type DirectiveOptions = V.DirectiveOptions
// plugin.d.ts // plugin.d.ts
export type PluginFunction<T> = V.PluginFunction<T>; export type PluginFunction<T> = V.PluginFunction<T>
export type PluginObject<T> = V.PluginObject<T>; export type PluginObject<T> = V.PluginObject<T>
// vnode.d.ts // vnode.d.ts
export type VNodeChildren = V.VNodeChildren; export type VNodeChildren = V.VNodeChildren
export type VNodeChildrenArrayContents = V.VNodeChildrenArrayContents; export type VNodeChildrenArrayContents = V.VNodeChildrenArrayContents
export type VNode = V.VNode; export type VNode = V.VNode
export type VNodeComponentOptions = V.VNodeComponentOptions; export type VNodeComponentOptions = V.VNodeComponentOptions
export type VNodeData = V.VNodeData; export type VNodeData = V.VNodeData
export type VNodeDirective = V.VNodeDirective; export type VNodeDirective = V.VNodeDirective
} }
declare class Vue extends V.default {} declare class Vue extends V.default {}
export = Vue; export = Vue
export as namespace Vue; export as namespace Vue

13
types/v3.d.ts vendored Normal file
View File

@ -0,0 +1,13 @@
import { VNode } from './vnode'
import { CreateElement, Vue } from './vue'
export interface SetupContext {
attrs: Record<string, any>
slots: Record<string, (() => VNode[]) | undefined>
emit: (event: string, ...args: any[]) => any
expose: (exposed?: Record<string, any>) => void
}
export function getCurrentInstance(): { proxy: Vue } | null
export const h: CreateElement

127
types/vnode.d.ts vendored
View File

@ -1,76 +1,89 @@
import { Vue } from "./vue"; import { Vue } from './vue'
export type ScopedSlot = (props: any) => ScopedSlotReturnValue; export type ScopedSlot = (props: any) => ScopedSlotReturnValue
type ScopedSlotReturnValue = VNode | string | boolean | null | undefined | ScopedSlotReturnArray; type ScopedSlotReturnValue =
| VNode
| string
| boolean
| null
| undefined
| ScopedSlotReturnArray
interface ScopedSlotReturnArray extends Array<ScopedSlotReturnValue> {} interface ScopedSlotReturnArray extends Array<ScopedSlotReturnValue> {}
// Scoped slots are guaranteed to return Array of VNodes starting in 2.6 // Scoped slots are guaranteed to return Array of VNodes starting in 2.6
export type NormalizedScopedSlot = (props: any) => ScopedSlotChildren; export type NormalizedScopedSlot = (props: any) => ScopedSlotChildren
export type ScopedSlotChildren = VNode[] | undefined; export type ScopedSlotChildren = VNode[] | undefined
// Relaxed type compatible with $createElement // Relaxed type compatible with $createElement
export type VNodeChildren = VNodeChildrenArrayContents | [ScopedSlot] | string | boolean | null | undefined; export type VNodeChildren =
export interface VNodeChildrenArrayContents extends Array<VNodeChildren | VNode> {} | VNodeChildrenArrayContents
| [ScopedSlot]
| string
| boolean
| null
| undefined
export interface VNodeChildrenArrayContents
extends Array<VNodeChildren | VNode> {}
export interface VNode { export interface VNode {
tag?: string; tag?: string
data?: VNodeData; data?: VNodeData
children?: VNode[]; children?: VNode[]
text?: string; text?: string
elm?: Node; elm?: Node
ns?: string; ns?: string
context?: Vue; context?: Vue
key?: string | number | symbol | boolean; key?: string | number | symbol | boolean
componentOptions?: VNodeComponentOptions; componentOptions?: VNodeComponentOptions
componentInstance?: Vue; componentInstance?: Vue
parent?: VNode; parent?: VNode
raw?: boolean; raw?: boolean
isStatic?: boolean; isStatic?: boolean
isRootInsert: boolean; isRootInsert: boolean
isComment: boolean; isComment: boolean
} }
export interface VNodeComponentOptions { export interface VNodeComponentOptions {
Ctor: typeof Vue; Ctor: typeof Vue
propsData?: object; propsData?: object
listeners?: object; listeners?: object
children?: VNode[]; children?: VNode[]
tag?: string; tag?: string
} }
export interface VNodeData { export interface VNodeData {
key?: string | number; key?: string | number
slot?: string; slot?: string
scopedSlots?: { [key: string]: ScopedSlot | undefined }; scopedSlots?: { [key: string]: ScopedSlot | undefined }
ref?: string; ref?: string
refInFor?: boolean; refInFor?: boolean
tag?: string; tag?: string
staticClass?: string; staticClass?: string
class?: any; class?: any
staticStyle?: { [key: string]: any }; staticStyle?: { [key: string]: any }
style?: string | object[] | object; style?: string | object[] | object
props?: { [key: string]: any }; props?: { [key: string]: any }
attrs?: { [key: string]: any }; attrs?: { [key: string]: any }
domProps?: { [key: string]: any }; domProps?: { [key: string]: any }
hook?: { [key: string]: Function }; hook?: { [key: string]: Function }
on?: { [key: string]: Function | Function[] }; on?: { [key: string]: Function | Function[] }
nativeOn?: { [key: string]: Function | Function[] }; nativeOn?: { [key: string]: Function | Function[] }
transition?: object; transition?: object
show?: boolean; show?: boolean
inlineTemplate?: { inlineTemplate?: {
render: Function; render: Function
staticRenderFns: Function[]; staticRenderFns: Function[]
}; }
directives?: VNodeDirective[]; directives?: VNodeDirective[]
keepAlive?: boolean; keepAlive?: boolean
} }
export interface VNodeDirective { export interface VNodeDirective {
name: string; name: string
value?: any; value?: any
oldValue?: any; oldValue?: any
expression?: string; expression?: string
arg?: string; arg?: string
oldArg?: string; oldArg?: string
modifiers?: { [key: string]: boolean }; modifiers?: { [key: string]: boolean }
} }

370
types/vue.d.ts vendored
View File

@ -10,123 +10,327 @@ import {
RecordPropsDefinition, RecordPropsDefinition,
ThisTypedComponentOptionsWithArrayProps, ThisTypedComponentOptionsWithArrayProps,
ThisTypedComponentOptionsWithRecordProps, ThisTypedComponentOptionsWithRecordProps,
WatchOptions, WatchOptions
} from "./options"; } from './options'
import { VNode, VNodeData, VNodeChildren, NormalizedScopedSlot } from "./vnode"; import { VNode, VNodeData, VNodeChildren, NormalizedScopedSlot } from './vnode'
import { PluginFunction, PluginObject } from "./plugin"; import { PluginFunction, PluginObject } from './plugin'
export interface CreateElement { export interface CreateElement {
(tag?: string | Component<any, any, any, any> | AsyncComponent<any, any, any, any> | (() => Component), children?: VNodeChildren): VNode; (
(tag?: string | Component<any, any, any, any> | AsyncComponent<any, any, any, any> | (() => Component), data?: VNodeData, children?: VNodeChildren): VNode; tag?:
| string
| Component<any, any, any, any>
| AsyncComponent<any, any, any, any>
| (() => Component),
children?: VNodeChildren
): VNode
(
tag?:
| string
| Component<any, any, any, any>
| AsyncComponent<any, any, any, any>
| (() => Component),
data?: VNodeData,
children?: VNodeChildren
): VNode
} }
export interface Vue { export interface Vue {
readonly $el: Element; readonly $el: Element
readonly $options: ComponentOptions<Vue>; readonly $options: ComponentOptions<Vue>
readonly $parent: Vue; readonly $parent: Vue
readonly $root: Vue; readonly $root: Vue
readonly $children: Vue[]; readonly $children: Vue[]
readonly $refs: { [key: string]: Vue | Element | (Vue | Element)[] | undefined }; readonly $refs: {
readonly $slots: { [key: string]: VNode[] | undefined }; [key: string]: Vue | Element | (Vue | Element)[] | undefined
readonly $scopedSlots: { [key: string]: NormalizedScopedSlot | undefined }; }
readonly $isServer: boolean; readonly $slots: { [key: string]: VNode[] | undefined }
readonly $data: Record<string, any>; readonly $scopedSlots: { [key: string]: NormalizedScopedSlot | undefined }
readonly $props: Record<string, any>; readonly $isServer: boolean
readonly $ssrContext: any; readonly $data: Record<string, any>
readonly $vnode: VNode; readonly $props: Record<string, any>
readonly $attrs: Record<string, string>; readonly $ssrContext: any
readonly $listeners: Record<string, Function | Function[]>; readonly $vnode: VNode
readonly $attrs: Record<string, string>
readonly $listeners: Record<string, Function | Function[]>
$mount(elementOrSelector?: Element | string, hydrating?: boolean): this; $mount(elementOrSelector?: Element | string, hydrating?: boolean): this
$forceUpdate(): void; $forceUpdate(): void
$destroy(): void; $destroy(): void
$set: typeof Vue.set; $set: typeof Vue.set
$delete: typeof Vue.delete; $delete: typeof Vue.delete
$watch( $watch(
expOrFn: string, expOrFn: string,
callback: (this: this, n: any, o: any) => void, callback: (this: this, n: any, o: any) => void,
options?: WatchOptions options?: WatchOptions
): (() => void); ): () => void
$watch<T>( $watch<T>(
expOrFn: (this: this) => T, expOrFn: (this: this) => T,
callback: (this: this, n: T, o: T) => void, callback: (this: this, n: T, o: T) => void,
options?: WatchOptions options?: WatchOptions
): (() => void); ): () => void
$on(event: string | string[], callback: Function): this; $on(event: string | string[], callback: Function): this
$once(event: string | string[], callback: Function): this; $once(event: string | string[], callback: Function): this
$off(event?: string | string[], callback?: Function): this; $off(event?: string | string[], callback?: Function): this
$emit(event: string, ...args: any[]): this; $emit(event: string, ...args: any[]): this
$nextTick(callback: (this: this) => void): void; $nextTick(callback: (this: this) => void): void
$nextTick(): Promise<void>; $nextTick(): Promise<void>
$createElement: CreateElement; $createElement: CreateElement
} }
export type CombinedVueInstance<Instance extends Vue, Data, Methods, Computed, Props> = Data & Methods & Computed & Props & Instance; export type CombinedVueInstance<
export type ExtendedVue<Instance extends Vue, Data, Methods, Computed, Props> = VueConstructor<CombinedVueInstance<Instance, Data, Methods, Computed, Props> & Vue>; Instance extends Vue,
Data,
Methods,
Computed,
Props,
SetupBindings
> = Data & Methods & Computed & Props & Instance & SetupBindings
export type ExtendedVue<
Instance extends Vue,
Data,
Methods,
Computed,
Props,
SetupBindings
> = VueConstructor<
CombinedVueInstance<Instance, Data, Methods, Computed, Props, SetupBindings> &
Vue
>
export interface VueConfiguration { export interface VueConfiguration {
silent: boolean; silent: boolean
optionMergeStrategies: any; optionMergeStrategies: any
devtools: boolean; devtools: boolean
productionTip: boolean; productionTip: boolean
performance: boolean; performance: boolean
errorHandler(err: Error, vm: Vue, info: string): void; errorHandler(err: Error, vm: Vue, info: string): void
warnHandler(msg: string, vm: Vue, trace: string): void; warnHandler(msg: string, vm: Vue, trace: string): void
ignoredElements: (string | RegExp)[]; ignoredElements: (string | RegExp)[]
keyCodes: { [key: string]: number | number[] }; keyCodes: { [key: string]: number | number[] }
async: boolean; async: boolean
} }
export interface VueConstructor<V extends Vue = Vue> { export interface VueConstructor<V extends Vue = Vue> {
new <Data = object, Methods = object, Computed = object, PropNames extends string = never>(options?: ThisTypedComponentOptionsWithArrayProps<V, Data, Methods, Computed, PropNames>): CombinedVueInstance<V, Data, Methods, Computed, Record<PropNames, any>>; /**
// ideally, the return type should just contain Props, not Record<keyof Props, any>. But TS requires to have Base constructors with the same return type. * new with array props
new <Data = object, Methods = object, Computed = object, Props = object>(options?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): CombinedVueInstance<V, Data, Methods, Computed, Record<keyof Props, any>>; */
new (options?: ComponentOptions<V>): CombinedVueInstance<V, object, object, object, Record<keyof object, any>>; new <
Data = object,
Methods = object,
Computed = object,
PropNames extends string = never,
SetupBindings = {}
>(
options?: ThisTypedComponentOptionsWithArrayProps<
V,
Data,
Methods,
Computed,
PropNames,
SetupBindings
>
): CombinedVueInstance<
V,
Data,
Methods,
Computed,
Record<PropNames, any>,
SetupBindings
>
extend<Data, Methods, Computed, PropNames extends string = never>(options?: ThisTypedComponentOptionsWithArrayProps<V, Data, Methods, Computed, PropNames>): ExtendedVue<V, Data, Methods, Computed, Record<PropNames, any>>; /**
extend<Data, Methods, Computed, Props>(options?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): ExtendedVue<V, Data, Methods, Computed, Props>; * new with object props
extend<PropNames extends string = never>(definition: FunctionalComponentOptions<Record<PropNames, any>, PropNames[]>): ExtendedVue<V, {}, {}, {}, Record<PropNames, any>>; * ideally, the return type should just contain Props,
extend<Props>(definition: FunctionalComponentOptions<Props, RecordPropsDefinition<Props>>): ExtendedVue<V, {}, {}, {}, Props>; * not Record<keyof Props, any>. But TS requires to have Base constructors
extend(options?: ComponentOptions<V>): ExtendedVue<V, {}, {}, {}, {}>; * with the same return type.
*/
new <
Data = object,
Methods = object,
Computed = object,
Props = object,
SetupBindings = {}
>(
options?: ThisTypedComponentOptionsWithRecordProps<
V,
Data,
Methods,
Computed,
Props,
SetupBindings
>
): CombinedVueInstance<
V,
Data,
Methods,
Computed,
Record<keyof Props, any>,
SetupBindings
>
nextTick<T>(callback: (this: T) => void, context?: T): void; /**
* new with no props
*/
new (options?: ComponentOptions<V>): CombinedVueInstance<
V,
object,
object,
object,
Record<keyof object, any>,
{}
>
/**
* extend with array props
*/
extend<
Data,
Methods,
Computed,
PropNames extends string = never,
SetupBindings = {}
>(
options?: ThisTypedComponentOptionsWithArrayProps<
V,
Data,
Methods,
Computed,
PropNames,
SetupBindings
>
): ExtendedVue<
V,
Data,
Methods,
Computed,
Record<PropNames, any>,
SetupBindings
>
/**
* extend with object props
*/
extend<Data, Methods, Computed, Props, SetupBindings = {}>(
options?: ThisTypedComponentOptionsWithRecordProps<
V,
Data,
Methods,
Computed,
Props,
SetupBindings
>
): ExtendedVue<V, Data, Methods, Computed, Props, SetupBindings>
/**
* extend with functional + array props
*/
extend<PropNames extends string = never>(
definition: FunctionalComponentOptions<Record<PropNames, any>, PropNames[]>
): ExtendedVue<V, {}, {}, {}, Record<PropNames, any>, {}>
/**
* extend with functional + object props
*/
extend<Props>(
definition: FunctionalComponentOptions<Props, RecordPropsDefinition<Props>>
): ExtendedVue<V, {}, {}, {}, Props, {}>
/**
* extend with no props
*/
extend(options?: ComponentOptions<V>): ExtendedVue<V, {}, {}, {}, {}, {}>
nextTick<T>(callback: (this: T) => void, context?: T): void
nextTick(): Promise<void> nextTick(): Promise<void>
set<T>(object: object, key: string | number, value: T): T; set<T>(object: object, key: string | number, value: T): T
set<T>(array: T[], key: number, value: T): T; set<T>(array: T[], key: number, value: T): T
delete(object: object, key: string | number): void; delete(object: object, key: string | number): void
delete<T>(array: T[], key: number): void; delete<T>(array: T[], key: number): void
directive( directive(
id: string, id: string,
definition?: DirectiveOptions | DirectiveFunction definition?: DirectiveOptions | DirectiveFunction
): DirectiveOptions; ): DirectiveOptions
filter(id: string, definition?: Function): Function; filter(id: string, definition?: Function): Function
component(id: string): VueConstructor; component(id: string): VueConstructor
component<VC extends VueConstructor>(id: string, constructor: VC): VC; component<VC extends VueConstructor>(id: string, constructor: VC): VC
component<Data, Methods, Computed, Props>(id: string, definition: AsyncComponent<Data, Methods, Computed, Props>): ExtendedVue<V, Data, Methods, Computed, Props>; component<Data, Methods, Computed, Props, SetupBindings>(
component<Data, Methods, Computed, PropNames extends string = never>(id: string, definition?: ThisTypedComponentOptionsWithArrayProps<V, Data, Methods, Computed, PropNames>): ExtendedVue<V, Data, Methods, Computed, Record<PropNames, any>>; id: string,
component<Data, Methods, Computed, Props>(id: string, definition?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): ExtendedVue<V, Data, Methods, Computed, Props>; definition: AsyncComponent<Data, Methods, Computed, Props>
component<PropNames extends string>(id: string, definition: FunctionalComponentOptions<Record<PropNames, any>, PropNames[]>): ExtendedVue<V, {}, {}, {}, Record<PropNames, any>>; ): ExtendedVue<V, Data, Methods, Computed, Props, SetupBindings>
component<Props>(id: string, definition: FunctionalComponentOptions<Props, RecordPropsDefinition<Props>>): ExtendedVue<V, {}, {}, {}, Props>; component<
component(id: string, definition?: ComponentOptions<V>): ExtendedVue<V, {}, {}, {}, {}>; Data,
Methods,
Computed,
PropNames extends string = never,
SetupBindings = {}
>(
id: string,
definition?: ThisTypedComponentOptionsWithArrayProps<
V,
Data,
Methods,
Computed,
PropNames,
SetupBindings
>
): ExtendedVue<
V,
Data,
Methods,
Computed,
Record<PropNames, any>,
SetupBindings
>
component<Data, Methods, Computed, Props, SetupBindings>(
id: string,
definition?: ThisTypedComponentOptionsWithRecordProps<
V,
Data,
Methods,
Computed,
Props,
SetupBindings
>
): ExtendedVue<V, Data, Methods, Computed, Props, SetupBindings>
component<PropNames extends string>(
id: string,
definition: FunctionalComponentOptions<Record<PropNames, any>, PropNames[]>
): ExtendedVue<V, {}, {}, {}, Record<PropNames, any>, {}>
component<Props>(
id: string,
definition: FunctionalComponentOptions<Props, RecordPropsDefinition<Props>>
): ExtendedVue<V, {}, {}, {}, Props, {}>
component(
id: string,
definition?: ComponentOptions<V>
): ExtendedVue<V, {}, {}, {}, {}, {}>
use<T>(plugin: PluginObject<T> | PluginFunction<T>, options?: T): VueConstructor<V>; use<T>(
use(plugin: PluginObject<any> | PluginFunction<any>, ...options: any[]): VueConstructor<V>; plugin: PluginObject<T> | PluginFunction<T>,
mixin(mixin: VueConstructor | ComponentOptions<Vue>): VueConstructor<V>; options?: T
): VueConstructor<V>
use(
plugin: PluginObject<any> | PluginFunction<any>,
...options: any[]
): VueConstructor<V>
mixin(mixin: VueConstructor | ComponentOptions<Vue>): VueConstructor<V>
compile(template: string): { compile(template: string): {
render(createElement: typeof Vue.prototype.$createElement): VNode; render(createElement: typeof Vue.prototype.$createElement): VNode
staticRenderFns: (() => VNode)[]; staticRenderFns: (() => VNode)[]
}; }
observable<T>(obj: T): T; observable<T>(obj: T): T
util: { util: {
warn(msg: string, vm?: InstanceType<VueConstructor>): void; warn(msg: string, vm?: InstanceType<VueConstructor>): void
}; }
config: VueConfiguration; config: VueConfiguration
version: string; version: string
} }
export const Vue: VueConstructor; export const Vue: VueConstructor