Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Further improve Vue type declarations for canonical usage #6391

Merged
merged 56 commits into from
Oct 6, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
5b5a88f
refactor TypeScript typings to use ES style exports
yyx990803 Feb 26, 2017
385a744
Allow functions in 'methods' & 'computed' to view themselves, as well…
DanielRosenwasser Mar 8, 2017
8cd5b9c
Got 'new Vue(...)', 'Vue.extend(...)', and 'Vue.component(...)' working.
DanielRosenwasser Mar 16, 2017
540a38f
Made it so that any 'data' function can only access 'props' and base …
DanielRosenwasser Mar 27, 2017
f34f4f6
Improved defaults, fixed overloads and types for functional component…
DanielRosenwasser Jun 1, 2017
b1f40ce
Condensed declaration of 'watch'.
DanielRosenwasser Jun 1, 2017
355ff75
Added two tests for 'extend'.
DanielRosenwasser Jun 1, 2017
bc54007
.\types\options.d.ts
DanielRosenwasser Jun 1, 2017
e7ea5bb
Updated tests, tighted strictness.
DanielRosenwasser Jun 1, 2017
ebde0b1
Merge remote-tracking branch 'upstream/dev' into accurateVueTypes
DanielRosenwasser Jun 1, 2017
d78d14b
Made the Vue instance non-generic, made readonly, augmented tests.
DanielRosenwasser Jun 14, 2017
fc83771
Make it possible to extend Vue without type arguments.
DanielRosenwasser Jun 14, 2017
a50c838
Removed 'ThisTypedComponentOptions'.
DanielRosenwasser Jun 14, 2017
3c86b10
Merge remote-tracking branch 'upstream/dev' into accurateVueTypes
DanielRosenwasser Jun 14, 2017
33a106c
Upgraded dependency on TypeScript.
DanielRosenwasser Jun 15, 2017
0f586db
Added test by @ktsn.
DanielRosenwasser Jun 15, 2017
1092efe
Removed unnecessary mixin constructors, made 'VueConstructor' generic.
DanielRosenwasser Jun 15, 2017
ebd8c0b
Merge remote-tracking branch 'upstream/dev' into accurateVueTypes
DanielRosenwasser Jun 23, 2017
c628103
[release] weex-vue-framework@2.4.2-weex.1 (#6196)
Hanks10100 Jul 24, 2017
e4a8545
Merge remote-tracking branch 'upstream/dev' into accurateVueTypes
DanielRosenwasser Jul 28, 2017
3cac5c7
fix-Firefox (#6359)
HiWangyeah Aug 13, 2017
d55bc63
feat(typing): compatible interface declaration
HerringtonDarkholme Aug 16, 2017
07eb21c
improve typing and tests
HerringtonDarkholme Aug 16, 2017
e7777d7
Merge branch 'new-type' of github.com:HerringtonDarkholme/vue into ne…
HerringtonDarkholme Aug 17, 2017
21d62a1
fix(typing): change default computed typing
HerringtonDarkholme Aug 17, 2017
0958bda
feat(typing): add more specific prop typing
HerringtonDarkholme Aug 17, 2017
6c76c45
feat(typing): refine props
HerringtonDarkholme Aug 17, 2017
5335788
fix(typing): fix some typing errors
HerringtonDarkholme Aug 17, 2017
8a1aab2
fix(typing): add async component back
HerringtonDarkholme Aug 17, 2017
042e1c3
test(typing): add small granular test
HerringtonDarkholme Aug 17, 2017
76de5dc
feat(typing): add ArrayProp back
HerringtonDarkholme Aug 17, 2017
070460b
feat(typing): add array types back
HerringtonDarkholme Aug 17, 2017
718dd7d
feat(typing): add array prop to extend/component
HerringtonDarkholme Aug 17, 2017
89f958b
feat(typing): add string prop test
HerringtonDarkholme Aug 17, 2017
da53a0a
fix(typing): add more compatibility test
HerringtonDarkholme Aug 17, 2017
e034641
fix(typing): address code review feedback
HerringtonDarkholme Aug 20, 2017
c9f0939
fix(typing): add cyclic test case
HerringtonDarkholme Aug 20, 2017
754d0df
feat(typing): add union type test
HerringtonDarkholme Aug 20, 2017
b784785
feat(typing): use call signatures
HerringtonDarkholme Aug 26, 2017
d5fbd81
fix(typing): add tests for regexp and array
HerringtonDarkholme Aug 28, 2017
37c5883
feat(typing): label props as readonly
HerringtonDarkholme Aug 29, 2017
9e6931a
fix(typing): this in beforeCreate is plain Vue
HerringtonDarkholme Aug 29, 2017
d9accb0
fix(typing): fix beforeCreate test
HerringtonDarkholme Aug 29, 2017
b90386a
fix(typing): use extended typing
HerringtonDarkholme Aug 29, 2017
67eab9c
chore: update backers
yyx990803 Aug 3, 2017
97a401e
Merge branch 'dev' of github.com:vuejs/vue into new-type
HerringtonDarkholme Aug 29, 2017
8df15b7
Merge branch 'dev' of github.com:vuejs/vue into new-type
HerringtonDarkholme Sep 6, 2017
1ac0b7a
Merge branch 'new-type' of github.com:HerringtonDarkholme/vue into ne…
HerringtonDarkholme Sep 6, 2017
4649739
Simplify 'CreateElement', remove potential error in 'AsyncComponent' …
DanielRosenwasser Sep 9, 2017
c953990
Simplify down to two overloads.
DanielRosenwasser Sep 11, 2017
8901752
Merge pull request #1 from DanielRosenwasser/simplifyCreateElement
HerringtonDarkholme Sep 12, 2017
a7f84d9
Merge branch 'dev' of github.com:vuejs/vue into new-type
HerringtonDarkholme Sep 14, 2017
5fa1ab9
Merge branch 'new-type' of github.com:HerringtonDarkholme/vue into ne…
HerringtonDarkholme Sep 14, 2017
a595239
fix(typing): fix functional component typing
HerringtonDarkholme Sep 14, 2017
00aa9d3
Merge branch 'dev' of github.com:vuejs/vue into new-type
HerringtonDarkholme Sep 17, 2017
6091248
Merge branch 'dev' of github.com:vuejs/vue into new-type
HerringtonDarkholme Sep 18, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(typing): add more specific prop typing
  • Loading branch information
HerringtonDarkholme committed Aug 17, 2017
commit 0958bda45a43817ca73f08037f419fba7a1c02f0
46 changes: 32 additions & 14 deletions types/options.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ export type ThisTypedComponentOptionsWithRecordProps<V extends Vue, Data, Method
* A helper type that describes options for either functional or non-functional components.
* Useful for `Vue.extend` and `Vue.component`.
*/
export type FunctionalOrStandardComponentOptions<Data, Methods, Computed, PropNames extends string = never> =
| FunctionalComponentOptions<PropNames[] | Record<PropNames, PropValidator>, Record<PropNames, any>>
| ThisTypedComponentOptionsWithArrayProps<Vue, Data, Methods, Computed, PropNames>
| ThisTypedComponentOptionsWithRecordProps<Vue, Data, Methods, Computed, Record<PropNames, PropOptions>>;
export type FunctionalOrStandardComponentOptions<Data, Methods, Computed, Props> =
| FunctionalComponentOptions<Props>
| ThisTypedComponentOptionsWithArrayProps<Vue, Data, Methods, Computed, keyof Props>
| ThisTypedComponentOptionsWithRecordProps<Vue, Data, Methods, Computed, Props>;

type DefaultData<V> = object | ((this: V) => object);
type DefaultProp = string[] | { [key: string]: PropOptions | Constructor | Constructor[] };
type DefaultProp = Record<string, any>;
type DefaultMethods<V> = { [key: string]: (this: V, ...args: any[]) => any };
type DefaultComputed = { [key: string]: any };
export interface ComponentOptions<
Expand All @@ -60,7 +60,7 @@ export interface ComponentOptions<
Computed=DefaultComputed,
Props=DefaultProp> {
data?: Data;
props?: Props;
props?: (keyof Props)[] | PropsDefinition<Props>;
propsData?: Object;
computed?: Accessors<Computed>;
methods?: Methods;
Expand Down Expand Up @@ -97,7 +97,7 @@ export interface ComponentOptions<
};

parent?: Vue;
mixins?: (ComponentOptions<any, any, any, any> | typeof Vue)[];
mixins?: (ComponentOptions<Vue> | typeof Vue)[];
name?: string;
// TODO: support properly inferred 'extends'
extends?: ComponentOptions<any, any, any, any> | typeof Vue;
Expand All @@ -106,11 +106,11 @@ export interface ComponentOptions<
inheritAttrs?: boolean;
}

export interface FunctionalComponentOptions<Props = object, ContextProps = object> {
export interface FunctionalComponentOptions<Props> {
name?: string;
props?: Props;
props?: keyof Props | PropsDefinition<Props>;
functional: boolean;
render(this: undefined, createElement: CreateElement, context: RenderContext<ContextProps>): VNode;
render(this: undefined, createElement: CreateElement, context: RenderContext<Props>): VNode;
}

export interface RenderContext<Props> {
Expand All @@ -122,15 +122,33 @@ export interface RenderContext<Props> {
injections: any
}

export type PropValidator = PropOptions | Constructor | Constructor[];
declare global {
interface StringConstructor {
'@@vueProp': string;
}
interface BooleanConstructor {
'@@vueProp': boolean;
}
interface NumberConstructor {
'@@vueProp': number;
}
}

export type Prop<T> = { '@@vueProp': T } | { new (...args: any[]): T }

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

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

Choose a reason for hiding this comment

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

This is clever declaration :D

required?: boolean;
default?: string | number | boolean | null | undefined | (() => object);
default?: T | null | undefined | (() => object);
validator?(value: any): boolean;
Copy link
Member

Choose a reason for hiding this comment

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

Can we let value type to T since we can infer prop type now?

Copy link
Member Author

Choose a reason for hiding this comment

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

The point of validator is testing anything if it is of type T, so any is more appropriate here.

Copy link
Member

Choose a reason for hiding this comment

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

But at least its type is specified by type option, isn't it?
The other types than type is not come here on runtime.

Copy link
Member Author

Choose a reason for hiding this comment

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

Indeed, I forget there is builtin check before validator!

}

export type PropsDefinition<T> = {
[K in keyof T]: PropValidator<T[K]>
}

export interface ComputedOptions<T> {
get?(): T;
set?(value: T): void;
Expand Down
16 changes: 5 additions & 11 deletions types/vue.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,10 @@ export type CombinedVueInstance<Instance extends Vue, Data, Methods, Computed, P
export type ExtendedVue<Instance extends Vue, Data, Methods, Computed, Props> = VueConstructor<CombinedVueInstance<Instance, Data, Methods, Computed, Props> & 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>>;
new <Data = object, Methods = object, Computed = object, Props extends Record<string, PropValidator> = {}>(options?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): CombinedVueInstance<V, Data, Methods, Computed, Record<keyof Props, any>>;
new <Data = object, Methods = object, Computed = object, Props = object>(options?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): CombinedVueInstance<V, Data, Methods, Computed, Props>;

extend<PropNames extends string = never>(definition: FunctionalComponentOptions<PropNames[], Record<PropNames, any>>): ExtendedVue<V, {}, {}, {}, Record<PropNames, any>>;
extend<Props extends Record<string, PropValidator>>(definition: FunctionalComponentOptions<Props, Record<keyof Props, any>>): ExtendedVue<V, {}, {}, {}, Record<keyof Props, any>>;
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 extends Record<string, PropValidator>>(options?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): ExtendedVue<V, Data, Methods, Computed, Record<keyof Props, any>>;
extend<Props>(definition: FunctionalComponentOptions<Props>): ExtendedVue<V, {}, {}, {}, Props>;
extend<Data, Methods, Computed, Props>(options?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): ExtendedVue<V, Data, Methods, Computed, Props>;

Choose a reason for hiding this comment

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

Having tried this out, while Props inference is great, I think there will be cases where someone will want to write an interface for props and then let Data, Methods, and Computed be inferred on their own, and then let

Maybe we should reorder this so that Props comes first? something like

extend<Props = Record<PropNames, any>, PropNames extends string = never, Data = {}, Methods = {}, Computed = {}>(options?: ThisTypedComponentOptionsWithArrayProps<V, Data, Methods, Computed, PropNames>): ExtendedVue<V, Data, Methods, Computed, Props>;
extend<Props = {}, Data = {}, Methods = {}, Computed = {}>(options?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): ExtendedVue<V, Data, Methods, Computed, Props>;

What do you think @HerringtonDarkholme?

Copy link
Member Author

Choose a reason for hiding this comment

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

I wonder if inferring default generic parameter is available in current TS. microsoft/TypeScript#14400 or this comment microsoft/TypeScript#13487 (comment)

So users have to annotate all the type parameters as long as they want to specify at least one parameter.

Choose a reason for hiding this comment

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

Unfortunately we haven't yet implemented that. This isn't a blocker though.

Copy link
Member

Choose a reason for hiding this comment

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

I'm merging this in preparation for 2.5 release. We can improve upon this in a separate PR later.

Copy link
Contributor

Choose a reason for hiding this comment

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

We were using this pattern below

interface AppComponent extends Store, Vue {
  // Additional typed props besides ones defined on Store here
}

export default {
// ...
} as ComponentOptions<AppComponent>

but it looks like this isn't possible with Vue 2.5 no more. Is there another way to type your props now? Possible workaround is to wrap props inside computed property with added type, but this isn't really elegant.


nextTick(callback: () => void, context?: any[]): void;
nextTick(): Promise<void>
Expand All @@ -100,11 +97,8 @@ export interface VueConstructor<V extends Vue = Vue> {

component(id: string): VueConstructor;
component<VC extends VueConstructor>(id: string, constructor: VC): VC;
component<Data, Methods, Computed, PropNames extends string = never>(id: string, definition: AsyncComponent<Data, Methods, Computed, PropNames>): ExtendedVue<V, Data, Methods, Computed, Record<PropNames, any>>;
component<PropNames extends string = never>(id: string, definition: FunctionalComponentOptions<PropNames[], Record<PropNames, any>>): ExtendedVue<V, {}, {}, {}, Record<PropNames, any>>;
component<Props extends Record<string, PropValidator>>(id: string, definition: FunctionalComponentOptions<Props, Record<keyof Props, any>>): ExtendedVue<V, {}, {}, {}, Record<keyof Props, any>>;
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>>;
component<Data, Methods, Computed, Props extends Record<string, PropValidator>>(id: string, definition?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): ExtendedVue<V, Data, Methods, Computed, Record<keyof Props, any>>;
component<Props>(id: string, definition: FunctionalComponentOptions<Props>): ExtendedVue<V, {}, {}, {}, Props>;
component<Data, Methods, Computed, Props>(id: string, definition?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): ExtendedVue<V, Data, Methods, Computed, Record<keyof Props, any>>;

use<T>(plugin: PluginObject<T> | PluginFunction<T>, options?: T): void;
mixin(mixin: typeof Vue | ComponentOptions<any, any, any, any>): void;
Expand Down