-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Further improve Vue type declarations for canonical usage #6391
Changes from 1 commit
5b5a88f
385a744
8cd5b9c
540a38f
f34f4f6
b1f40ce
355ff75
bc54007
e7ea5bb
ebde0b1
d78d14b
fc83771
a50c838
3c86b10
33a106c
0f586db
1092efe
ebd8c0b
c628103
e4a8545
3cac5c7
d55bc63
07eb21c
e7777d7
21d62a1
0958bda
6c76c45
5335788
8a1aab2
042e1c3
76de5dc
070460b
718dd7d
89f958b
da53a0a
e034641
c9f0939
754d0df
b784785
d5fbd81
37c5883
9e6931a
d9accb0
b90386a
67eab9c
97a401e
8df15b7
1ac0b7a
4649739
c953990
8901752
a7f84d9
5fa1ab9
a595239
00aa9d3
6091248
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
… as members from 'data' and the Vue instance.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,50 @@ | ||
import { Vue, CreateElement } from "./vue"; | ||
import { Vue, CreateElement, AnyVue } from "./vue"; | ||
import { VNode, VNodeData, VNodeDirective } from "./vnode"; | ||
|
||
type Constructor = { | ||
new (...args: any[]): any; | ||
} | ||
|
||
export type Component = typeof Vue | ComponentOptions<Vue> | FunctionalComponentOptions; | ||
export type AsyncComponent = ( | ||
resolve: (component: Component) => void, | ||
export type Component<Data = any, Methods = any, Computed = any> = typeof Vue | ComponentOptions<Data, Methods, Computed> | FunctionalComponentOptions; | ||
export type AsyncComponent<Data = any, Methods = any, Computed = any> = ( | ||
resolve: (component: Component<Data, Methods, Computed>) => void, | ||
reject: (reason?: any) => void | ||
) => Promise<Component> | Component | void; | ||
) => Promise<Component<Data, Methods, Computed>> | Component<Data, Methods, Computed> | void; | ||
|
||
/** | ||
* When the `Computed` type parameter on `ComponentOptions` is inferred, | ||
* it should have a property with the return type of every get-accessor. | ||
* Since there isn't a way to query for the return type of a function, we allow TypeScript | ||
* to infer from the shape of `Accessors<Computed>` and work backwards. | ||
*/ | ||
export type Accessors<T> = { | ||
[K in keyof T]: (() => T[K]) | ComputedOptions<T[K]> | ||
} | ||
|
||
export interface ComponentOptions<V extends Vue> { | ||
data?: Object | ((this: V) => Object); | ||
export interface ComponentOptions<Data, Methods, Computed> { | ||
data?: Data | (() => Data); | ||
props?: string[] | { [key: string]: PropOptions | Constructor | Constructor[] }; | ||
propsData?: Object; | ||
computed?: { [key: string]: ((this: V) => any) | ComputedOptions<V> }; | ||
methods?: { [key: string]: (this: V, ...args: any[]) => any }; | ||
watch?: { [key: string]: ({ handler: WatchHandler<V, any> } & WatchOptions) | WatchHandler<V, any> | string }; | ||
computed?: Accessors<Computed>; | ||
methods?: Methods; | ||
watch?: { [key: string]: ({ handler: WatchHandler<any> } & WatchOptions) | WatchHandler<any> | string }; | ||
|
||
el?: Element | String; | ||
template?: string; | ||
render?(this: V, createElement: CreateElement): VNode; | ||
render?(createElement: CreateElement): VNode; | ||
renderError?: (h: () => VNode, err: Error) => VNode; | ||
staticRenderFns?: ((createElement: CreateElement) => VNode)[]; | ||
|
||
beforeCreate?(this: V): void; | ||
created?(this: V): void; | ||
beforeDestroy?(this: V): void; | ||
destroyed?(this: V): void; | ||
beforeMount?(this: V): void; | ||
mounted?(this: V): void; | ||
beforeUpdate?(this: V): void; | ||
updated?(this: V): void; | ||
activated?(this: V): void; | ||
deactivated?(this: V): void; | ||
beforeCreate?(): void; | ||
created?(): void; | ||
beforeDestroy?(): void; | ||
destroyed?(): void; | ||
beforeMount?(): void; | ||
mounted?(): void; | ||
beforeUpdate?(): void; | ||
updated?(): void; | ||
activated?(): void; | ||
deactivated?(): void; | ||
|
||
directives?: { [key: string]: DirectiveOptions | DirectiveFunction }; | ||
components?: { [key: string]: Component | AsyncComponent }; | ||
|
@@ -49,10 +59,11 @@ export interface ComponentOptions<V extends Vue> { | |
event?: string; | ||
}; | ||
|
||
parent?: Vue; | ||
mixins?: (ComponentOptions<Vue> | typeof Vue)[]; | ||
parent?: AnyVue; | ||
mixins?: (ComponentOptions<any, any, any> | typeof Vue)[]; | ||
name?: string; | ||
extends?: ComponentOptions<Vue> | typeof Vue; | ||
// TODO: support properly inferred 'extends' | ||
extends?: ComponentOptions<any, any, any> | typeof Vue; | ||
delimiters?: [string, string]; | ||
} | ||
|
||
|
@@ -68,7 +79,7 @@ export interface RenderContext { | |
children: VNode[]; | ||
slots(): any; | ||
data: VNodeData; | ||
parent: Vue; | ||
parent: AnyVue; | ||
} | ||
|
||
export interface PropOptions { | ||
|
@@ -78,13 +89,13 @@ export interface PropOptions { | |
validator?(value: any): boolean; | ||
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. Can we let 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. The point of validator is testing 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. But at least its type is specified by 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. Indeed, I forget there is builtin check before validator! |
||
} | ||
|
||
export interface ComputedOptions<V> { | ||
get?(this: V): any; | ||
set?(this: V, value: any): void; | ||
export interface ComputedOptions<T> { | ||
get?(): T; | ||
set?(value: T): void; | ||
cache?: boolean; | ||
} | ||
|
||
export type WatchHandler<V, T> = (this: V, val: T, oldVal: T) => void; | ||
export type WatchHandler<T> = (val: T, oldVal: T) => void; | ||
|
||
export interface WatchOptions { | ||
deep?: boolean; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"compilerOptions": { | ||
"strict": true, | ||
"lib": [ | ||
"es2015", "dom" | ||
] | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,7 @@ import { | |
WatchOptions, | ||
WatchHandler, | ||
DirectiveOptions, | ||
DirectiveFunction | ||
DirectiveFunction, | ||
} from "./options"; | ||
import { VNode, VNodeData, VNodeChildren, ScopedSlot } from "./vnode"; | ||
import { PluginFunction, PluginObject } from "./plugin"; | ||
|
@@ -28,17 +28,17 @@ export type CreateElement = { | |
(tag: AsyncComponent, data?: VNodeData, children?: VNodeChildren): VNode; | ||
} | ||
|
||
export declare class Vue { | ||
|
||
constructor(options?: ComponentOptions<Vue>); | ||
interface AnyVue extends Vue<any, any, any> { | ||
} | ||
|
||
$data: Object; | ||
export interface Vue<Data, Methods, Computed> { | ||
$data: Data; | ||
readonly $el: HTMLElement; | ||
readonly $options: ComponentOptions<this>; | ||
readonly $parent: Vue; | ||
readonly $root: Vue; | ||
readonly $children: Vue[]; | ||
readonly $refs: { [key: string]: Vue | Element | Vue[] | Element[]}; | ||
readonly $options: ComponentOptions<Data, Methods, Computed>; | ||
readonly $parent: AnyVue; | ||
readonly $root: AnyVue; | ||
readonly $children: AnyVue[]; | ||
readonly $refs: { [key: string]: AnyVue | Element | AnyVue[] | Element[] }; | ||
readonly $slots: { [key: string]: VNode[] }; | ||
readonly $scopedSlots: { [key: string]: ScopedSlot }; | ||
readonly $isServer: boolean; | ||
|
@@ -51,12 +51,12 @@ export declare class Vue { | |
$delete: typeof Vue.delete; | ||
$watch( | ||
expOrFn: string, | ||
callback: WatchHandler<this, any>, | ||
callback: WatchHandler<any>, | ||
options?: WatchOptions | ||
): (() => void); | ||
$watch<T>( | ||
expOrFn: (this: this) => T, | ||
callback: WatchHandler<this, T>, | ||
callback: WatchHandler<T>, | ||
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. Maybe, we need to keep 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. Hmm. We cannot reuse WatchHandler because explicit this typing will break ThisType. Just write a new function type will be fine. |
||
options?: WatchOptions | ||
): (() => void); | ||
$on(event: string | string[], callback: Function): this; | ||
|
@@ -66,36 +66,42 @@ export declare class Vue { | |
$nextTick(callback: (this: this) => void): void; | ||
$nextTick(): Promise<void>; | ||
$createElement: CreateElement; | ||
} | ||
|
||
static config: { | ||
silent: boolean; | ||
optionMergeStrategies: any; | ||
devtools: boolean; | ||
productionTip: boolean; | ||
performance: boolean; | ||
errorHandler(err: Error, vm: Vue, info: string): void; | ||
ignoredElements: string[]; | ||
keyCodes: { [key: string]: number }; | ||
} | ||
export interface VueConstructor { | ||
new <Data, Methods, Computed>(options?: ComponentOptions<Data, Methods & ThisType<Data & Methods & Computed>, Computed> & ThisType<Data & Methods & Computed>): Data & Methods & Computed & Vue<Data, Methods, Computed>; | ||
|
||
static extend(options: ComponentOptions<Vue> | FunctionalComponentOptions): typeof Vue; | ||
static nextTick(callback: () => void, context?: any[]): void; | ||
static nextTick(): Promise<void> | ||
static set<T>(object: Object, key: string, value: T): T; | ||
static set<T>(array: T[], key: number, value: T): T; | ||
static delete(object: Object, key: string): void; | ||
extend<V, Data, Methods, Computed>(this: V, options: ComponentOptions<Data, Methods, Computed> | FunctionalComponentOptions): ((...args: any[]) => Vue<Data, Methods, Computed>) & V; | ||
nextTick(callback: () => void, context?: any[]): void; | ||
nextTick(): Promise<void> | ||
set<T>(object: Object, key: string, value: T): T; | ||
set<T>(array: T[], key: number, value: T): T; | ||
delete(object: Object, key: string): void; | ||
|
||
static directive( | ||
directive( | ||
id: string, | ||
definition?: DirectiveOptions | DirectiveFunction | ||
): DirectiveOptions; | ||
static filter(id: string, definition?: Function): Function; | ||
static component(id: string, definition?: Component | AsyncComponent): typeof Vue; | ||
filter(id: string, definition?: Function): Function; | ||
component(id: string, definition?: Component | AsyncComponent): typeof Vue; | ||
|
||
static use<T>(plugin: PluginObject<T> | PluginFunction<T>, options?: T): void; | ||
static mixin(mixin: typeof Vue | ComponentOptions<Vue>): void; | ||
static compile(template: string): { | ||
use<T>(plugin: PluginObject<T> | PluginFunction<T>, options?: T): void; | ||
mixin(mixin: typeof Vue | ComponentOptions<any, any, any>): void; | ||
compile(template: string): { | ||
render(createElement: typeof Vue.prototype.$createElement): VNode; | ||
staticRenderFns: (() => VNode)[]; | ||
}; | ||
|
||
config: { | ||
silent: boolean; | ||
optionMergeStrategies: any; | ||
devtools: boolean; | ||
productionTip: boolean; | ||
performance: boolean; | ||
errorHandler(err: Error, vm: AnyVue, info: string): void; | ||
ignoredElements: string[]; | ||
keyCodes: { [key: string]: number }; | ||
} | ||
} | ||
|
||
export const Vue: VueConstructor; |
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.
Looks like ThisType of
computed
,watch
,render
and lifecycle hooks will be invalid if the users annotate their component options withas ComponentOptions<Something>
.Can we deal with in that case too?
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.
Type assertion like
{ opt: ...} as Option
would not bring type inference to the declaration.Users have to annotate Vue.extend or casting
this
.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.
I see. Then I think we should stated about this in docs for migration 🙂