From 9a9672050bcfee198c379069ec0e1b03ca6cb965 Mon Sep 17 00:00:00 2001 From: katashin Date: Sun, 10 Nov 2019 22:53:49 +0800 Subject: [PATCH] fix(types): avoid broadening vue instance type when using map helpers (#1639) * fix(types): avoid broading vue instance type when using map helpers * refactor: add type restriction to helper types --- package.json | 2 +- types/helpers.d.ts | 69 +++++++++------ types/test/helpers.ts | 196 +++++++++++++++++++++++++----------------- yarn.lock | 8 +- 4 files changed, 165 insertions(+), 110 deletions(-) diff --git a/package.json b/package.json index 23f421901..753b2e29d 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "selenium-server": "^2.53.1", "terser": "^3.17.0", "todomvc-app-css": "^2.1.0", - "typescript": "^3.2.2", + "typescript": "^3.7.2", "vue": "^2.5.22", "vue-loader": "^15.2.1", "vue-template-compiler": "^2.5.22", diff --git a/types/helpers.d.ts b/types/helpers.d.ts index 36f1c7418..2de5cf9e5 100644 --- a/types/helpers.d.ts +++ b/types/helpers.d.ts @@ -1,51 +1,68 @@ import Vue from 'vue'; import { Dispatch, Commit } from './index'; -type Dictionary = { [key: string]: T }; type Computed = () => any; +type InlineComputed = T extends (...args: any[]) => infer R ? () => R : never type MutationMethod = (...args: any[]) => void; type ActionMethod = (...args: any[]) => Promise; -type CustomVue = Vue & Dictionary; +type InlineMethod any> = T extends (fn: any, ...args: infer Args) => infer R ? (...args: Args) => R : never +type CustomVue = Vue & Record; interface Mapper { - (map: string[]): Dictionary; - (map: Dictionary): Dictionary; + (map: Key[]): { [K in Key]: R }; + >(map: Map): { [K in keyof Map]: R }; } interface MapperWithNamespace { - (namespace: string, map: string[]): Dictionary; - (namespace: string, map: Dictionary): Dictionary; + (namespace: string, map: Key[]): { [K in Key]: R }; + >(namespace: string, map: Map): { [K in keyof Map]: R }; } -interface FunctionMapper { - (map: Dictionary<(this: CustomVue, fn: F, ...args: any[]) => any>): Dictionary; +interface MapperForState { + any> = {}>( + map: Map + ): { [K in keyof Map]: InlineComputed }; } -interface FunctionMapperWithNamespace { - ( +interface MapperForStateWithNamespace { + any> = {}>( namespace: string, - map: Dictionary<(this: CustomVue, fn: F, ...args: any[]) => any> - ): Dictionary; + map: Map + ): { [K in keyof Map]: InlineComputed }; } -interface MapperForState { - ( - map: Dictionary<(this: CustomVue, state: S, getters: any) => any> - ): Dictionary; +interface MapperForAction { + any>>( + map: Map + ): { [K in keyof Map]: InlineMethod }; } -interface MapperForStateWithNamespace { - ( +interface MapperForActionWithNamespace { + any>>( + namespace: string, + map: Map + ): { [K in keyof Map]: InlineMethod }; +} + +interface MapperForMutation { + any>>( + map: Map + ): { [K in keyof Map]: InlineMethod }; +} + +interface MapperForMutationWithNamespace { + any>>( namespace: string, - map: Dictionary<(this: CustomVue, state: S, getters: any) => any> - ): Dictionary; + map: Map + ): { [K in keyof Map]: InlineMethod }; } + interface NamespacedMappers { mapState: Mapper & MapperForState; - mapMutations: Mapper & FunctionMapper; + mapMutations: Mapper & MapperForMutation; mapGetters: Mapper; - mapActions: Mapper & FunctionMapper; + mapActions: Mapper & MapperForAction; } export declare const mapState: Mapper @@ -55,15 +72,15 @@ export declare const mapState: Mapper export declare const mapMutations: Mapper & MapperWithNamespace - & FunctionMapper - & FunctionMapperWithNamespace; + & MapperForMutation + & MapperForMutationWithNamespace; export declare const mapGetters: Mapper & MapperWithNamespace; export declare const mapActions: Mapper & MapperWithNamespace - & FunctionMapper - & FunctionMapperWithNamespace; + & MapperForAction + & MapperForActionWithNamespace; export declare function createNamespacedHelpers(namespace: string): NamespacedMappers; diff --git a/types/test/helpers.ts b/types/test/helpers.ts index 569a9ecaf..d1b64e5cb 100644 --- a/types/test/helpers.ts +++ b/types/test/helpers.ts @@ -11,79 +11,78 @@ import { const helpers = createNamespacedHelpers('foo'); new Vue({ - computed: Object.assign({}, - mapState(["a"]), - mapState('foo', ["a"]), - mapState({ - b: "b" + computed: { + ...mapState(["a"]), + ...mapState('foo', ["b"]), + ...mapState({ + c: "c" }), - mapState('foo', { - b: "b" + ...mapState('foo', { + d: "d" }), - mapState({ - c: (state: any, getters: any) => state.c + getters.c + ...mapState({ + e: (state: any, getters: any) => state.a + getters.g }), - mapState('foo', { - c: (state: any, getters: any) => state.c + getters.c + ...mapState('foo', { + f: (state: any, getters: any) => state.a + getters.g }), - mapGetters(["d"]), - mapGetters('foo', ["d"]), - mapGetters({ - e: "e" + ...mapGetters(["g"]), + ...mapGetters('foo', ["h"]), + ...mapGetters({ + i: "i" }), - mapGetters('foo', { - e: "e" + ...mapGetters('foo', { + j: "j" }), - helpers.mapState(["k"]), - helpers.mapState({ - k: "k" - }), - helpers.mapState({ - k: (state: any, getters: any) => state.k + getters.k, - useThis(state: any, getters: any) { - return state.k + getters.k + this.whatever + ...helpers.mapState(["k"]), + ...helpers.mapState({ + l: "l" + }), + ...helpers.mapState({ + m: (state: any, getters: any) => state.a + getters.g, + useThis(state: any, getters: any): any { + return state.a + getters.g + this.whatever } }), - helpers.mapGetters(["l"]), - helpers.mapGetters({ - l: "l" + ...helpers.mapGetters(["n"]), + ...helpers.mapGetters({ + o: "o" }), - { - otherComputed () { - return "f"; - } + + otherComputed () { + return ""; } - ), + }, - methods: Object.assign({}, - mapActions(["g"]), - mapActions({ - h: "h" - }), - mapActions({ - g (dispatch, a: string, b: number, c: boolean): void { - dispatch('g', { a, b, c }) + methods: { + ...mapActions(["p"]), + ...mapActions({ + q: "q" + }), + ...mapActions({ + r (dispatch, a: string, b: number, c: boolean) { + dispatch('p', { a, b, c }) dispatch({ - type: 'g', + type: 'p', a, b, c }) } }), - mapActions('foo', ["g"]), - mapActions('foo', { - h: "h" + ...mapActions('foo', ["s"]), + ...mapActions('foo', { + t: "t" }), - mapActions('foo', { - g (dispatch, a: string, b: number, c: boolean): void { - dispatch('g', { a, b, c }) + ...mapActions('foo', { + u (dispatch, a: string, b: number, c: boolean) { + dispatch('p', { a, b, c }) dispatch({ - type: 'g', + type: 'p', a, b, c @@ -91,30 +90,30 @@ new Vue({ } }), - mapMutations(["i"]), - mapMutations({ - j: "j" + ...mapMutations(["v"]), + ...mapMutations({ + w: "w" }), - mapMutations({ - i (commit, a: string, b: number, c: boolean): void { - commit('i', { a, b, c }) + ...mapMutations({ + x (commit, a: string, b: number, c: boolean) { + commit('v', { a, b, c }) commit({ - type: 'i', + type: 'v', a, b, c }) } }), - mapMutations('foo', ["i"]), - mapMutations('foo', { - j: "j" + ...mapMutations('foo', ["y"]), + ...mapMutations('foo', { + z: "z" }), - mapMutations('foo', { - i (commit, a: string, b: number, c: boolean): void { - commit('i', { a, b, c }) + ...mapMutations('foo', { + aa (commit, a: string, b: number, c: boolean) { + commit('v', { a, b, c }) commit({ - type: 'i', + type: 'v', a, b, c @@ -122,28 +121,67 @@ new Vue({ } }), - helpers.mapActions(["m"]), - helpers.mapActions({ - m: "m" + ...helpers.mapActions(["ab"]), + ...helpers.mapActions({ + ac: "ac" }), - helpers.mapActions({ - m (dispatch, value: string) { - dispatch('m', value) + ...helpers.mapActions({ + ad (dispatch, value: string) { + dispatch('p', value) } }), - helpers.mapMutations(["n"]), - helpers.mapMutations({ - n: "n" + ...helpers.mapMutations(["ae"]), + ...helpers.mapMutations({ + af: "af" }), - helpers.mapMutations({ - n (commit, value: string) { - commit('m', value) + ...helpers.mapMutations({ + ag (commit, value: string) { + commit('v', value) } }), - { - otherMethod () {} - } - ) + otherMethod () {} + }, + + created() { + // Computed + this.a + this.b + this.c + this.d + this.e + this.f + this.g + this.h + this.i + this.j + this.k + this.l + this.m + this.n + this.o + this.otherComputed + + // Methods + this.p() + this.q() + this.r('', 0, true) + this.s() + this.t() + this.u('', 0, true) + this.v() + this.w() + this.x('', 0, true) + this.y() + this.z() + this.aa('', 0, true) + this.ab() + this.ac() + this.ad('') + this.ae() + this.af() + this.ag('') + this.otherMethod() + } }); diff --git a/yarn.lock b/yarn.lock index 423a69868..1e11a430e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9071,10 +9071,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.2.tgz#fe8101c46aa123f8353523ebdcf5730c2ae493e5" - integrity sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg== +typescript@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.2.tgz#27e489b95fa5909445e9fef5ee48d81697ad18fb" + integrity sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ== uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.5"