Skip to content

Commit 9a96720

Browse files
authored
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
1 parent adab4aa commit 9a96720

File tree

4 files changed

+165
-110
lines changed

4 files changed

+165
-110
lines changed

Diff for: package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
"selenium-server": "^2.53.1",
6464
"terser": "^3.17.0",
6565
"todomvc-app-css": "^2.1.0",
66-
"typescript": "^3.2.2",
66+
"typescript": "^3.7.2",
6767
"vue": "^2.5.22",
6868
"vue-loader": "^15.2.1",
6969
"vue-template-compiler": "^2.5.22",

Diff for: types/helpers.d.ts

+43-26
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,68 @@
11
import Vue from 'vue';
22
import { Dispatch, Commit } from './index';
33

4-
type Dictionary<T> = { [key: string]: T };
54
type Computed = () => any;
5+
type InlineComputed<T extends Function> = T extends (...args: any[]) => infer R ? () => R : never
66
type MutationMethod = (...args: any[]) => void;
77
type ActionMethod = (...args: any[]) => Promise<any>;
8-
type CustomVue = Vue & Dictionary<any>;
8+
type InlineMethod<T extends (fn: any, ...args: any[]) => any> = T extends (fn: any, ...args: infer Args) => infer R ? (...args: Args) => R : never
9+
type CustomVue = Vue & Record<string, any>;
910

1011
interface Mapper<R> {
11-
(map: string[]): Dictionary<R>;
12-
(map: Dictionary<string>): Dictionary<R>;
12+
<Key extends string>(map: Key[]): { [K in Key]: R };
13+
<Map extends Record<string, string>>(map: Map): { [K in keyof Map]: R };
1314
}
1415

1516
interface MapperWithNamespace<R> {
16-
(namespace: string, map: string[]): Dictionary<R>;
17-
(namespace: string, map: Dictionary<string>): Dictionary<R>;
17+
<Key extends string>(namespace: string, map: Key[]): { [K in Key]: R };
18+
<Map extends Record<string, string>>(namespace: string, map: Map): { [K in keyof Map]: R };
1819
}
1920

20-
interface FunctionMapper<F, R> {
21-
(map: Dictionary<(this: CustomVue, fn: F, ...args: any[]) => any>): Dictionary<R>;
21+
interface MapperForState {
22+
<S, Map extends Record<string, (this: CustomVue, state: S, getters: any) => any> = {}>(
23+
map: Map
24+
): { [K in keyof Map]: InlineComputed<Map[K]> };
2225
}
2326

24-
interface FunctionMapperWithNamespace<F, R> {
25-
(
27+
interface MapperForStateWithNamespace {
28+
<S, Map extends Record<string, (this: CustomVue, state: S, getters: any) => any> = {}>(
2629
namespace: string,
27-
map: Dictionary<(this: CustomVue, fn: F, ...args: any[]) => any>
28-
): Dictionary<R>;
30+
map: Map
31+
): { [K in keyof Map]: InlineComputed<Map[K]> };
2932
}
3033

31-
interface MapperForState {
32-
<S>(
33-
map: Dictionary<(this: CustomVue, state: S, getters: any) => any>
34-
): Dictionary<Computed>;
34+
interface MapperForAction {
35+
<Map extends Record<string, (this: CustomVue, dispatch: Dispatch, ...args: any[]) => any>>(
36+
map: Map
37+
): { [K in keyof Map]: InlineMethod<Map[K]> };
3538
}
3639

37-
interface MapperForStateWithNamespace {
38-
<S>(
40+
interface MapperForActionWithNamespace {
41+
<Map extends Record<string, (this: CustomVue, dispatch: Dispatch, ...args: any[]) => any>>(
42+
namespace: string,
43+
map: Map
44+
): { [K in keyof Map]: InlineMethod<Map[K]> };
45+
}
46+
47+
interface MapperForMutation {
48+
<Map extends Record<string, (this: CustomVue, commit: Commit, ...args: any[]) => any>>(
49+
map: Map
50+
): { [K in keyof Map]: InlineMethod<Map[K]> };
51+
}
52+
53+
interface MapperForMutationWithNamespace {
54+
<Map extends Record<string, (this: CustomVue, commit: Commit, ...args: any[]) => any>>(
3955
namespace: string,
40-
map: Dictionary<(this: CustomVue, state: S, getters: any) => any>
41-
): Dictionary<Computed>;
56+
map: Map
57+
): { [K in keyof Map]: InlineMethod<Map[K]> };
4258
}
4359

60+
4461
interface NamespacedMappers {
4562
mapState: Mapper<Computed> & MapperForState;
46-
mapMutations: Mapper<MutationMethod> & FunctionMapper<Commit, MutationMethod>;
63+
mapMutations: Mapper<MutationMethod> & MapperForMutation;
4764
mapGetters: Mapper<Computed>;
48-
mapActions: Mapper<ActionMethod> & FunctionMapper<Dispatch, ActionMethod>;
65+
mapActions: Mapper<ActionMethod> & MapperForAction;
4966
}
5067

5168
export declare const mapState: Mapper<Computed>
@@ -55,15 +72,15 @@ export declare const mapState: Mapper<Computed>
5572

5673
export declare const mapMutations: Mapper<MutationMethod>
5774
& MapperWithNamespace<MutationMethod>
58-
& FunctionMapper<Commit, MutationMethod>
59-
& FunctionMapperWithNamespace<Commit, MutationMethod>;
75+
& MapperForMutation
76+
& MapperForMutationWithNamespace;
6077

6178
export declare const mapGetters: Mapper<Computed>
6279
& MapperWithNamespace<Computed>;
6380

6481
export declare const mapActions: Mapper<ActionMethod>
6582
& MapperWithNamespace<ActionMethod>
66-
& FunctionMapper<Dispatch, ActionMethod>
67-
& FunctionMapperWithNamespace<Dispatch, ActionMethod>;
83+
& MapperForAction
84+
& MapperForActionWithNamespace;
6885

6986
export declare function createNamespacedHelpers(namespace: string): NamespacedMappers;

Diff for: types/test/helpers.ts

+117-79
Original file line numberDiff line numberDiff line change
@@ -11,139 +11,177 @@ import {
1111
const helpers = createNamespacedHelpers('foo');
1212

1313
new Vue({
14-
computed: Object.assign({},
15-
mapState(["a"]),
16-
mapState('foo', ["a"]),
17-
mapState({
18-
b: "b"
14+
computed: {
15+
...mapState(["a"]),
16+
...mapState('foo', ["b"]),
17+
...mapState({
18+
c: "c"
1919
}),
20-
mapState('foo', {
21-
b: "b"
20+
...mapState('foo', {
21+
d: "d"
2222
}),
23-
mapState({
24-
c: (state: any, getters: any) => state.c + getters.c
23+
...mapState({
24+
e: (state: any, getters: any) => state.a + getters.g
2525
}),
26-
mapState('foo', {
27-
c: (state: any, getters: any) => state.c + getters.c
26+
...mapState('foo', {
27+
f: (state: any, getters: any) => state.a + getters.g
2828
}),
2929

30-
mapGetters(["d"]),
31-
mapGetters('foo', ["d"]),
32-
mapGetters({
33-
e: "e"
30+
...mapGetters(["g"]),
31+
...mapGetters('foo', ["h"]),
32+
...mapGetters({
33+
i: "i"
3434
}),
35-
mapGetters('foo', {
36-
e: "e"
35+
...mapGetters('foo', {
36+
j: "j"
3737
}),
3838

39-
helpers.mapState(["k"]),
40-
helpers.mapState({
41-
k: "k"
42-
}),
43-
helpers.mapState({
44-
k: (state: any, getters: any) => state.k + getters.k,
45-
useThis(state: any, getters: any) {
46-
return state.k + getters.k + this.whatever
39+
...helpers.mapState(["k"]),
40+
...helpers.mapState({
41+
l: "l"
42+
}),
43+
...helpers.mapState({
44+
m: (state: any, getters: any) => state.a + getters.g,
45+
useThis(state: any, getters: any): any {
46+
return state.a + getters.g + this.whatever
4747
}
4848
}),
4949

50-
helpers.mapGetters(["l"]),
51-
helpers.mapGetters({
52-
l: "l"
50+
...helpers.mapGetters(["n"]),
51+
...helpers.mapGetters({
52+
o: "o"
5353
}),
5454

55-
{
56-
otherComputed () {
57-
return "f";
58-
}
55+
56+
otherComputed () {
57+
return "";
5958
}
60-
),
59+
},
6160

62-
methods: Object.assign({},
63-
mapActions(["g"]),
64-
mapActions({
65-
h: "h"
66-
}),
67-
mapActions({
68-
g (dispatch, a: string, b: number, c: boolean): void {
69-
dispatch('g', { a, b, c })
61+
methods: {
62+
...mapActions(["p"]),
63+
...mapActions({
64+
q: "q"
65+
}),
66+
...mapActions({
67+
r (dispatch, a: string, b: number, c: boolean) {
68+
dispatch('p', { a, b, c })
7069
dispatch({
71-
type: 'g',
70+
type: 'p',
7271
a,
7372
b,
7473
c
7574
})
7675
}
7776
}),
78-
mapActions('foo', ["g"]),
79-
mapActions('foo', {
80-
h: "h"
77+
...mapActions('foo', ["s"]),
78+
...mapActions('foo', {
79+
t: "t"
8180
}),
82-
mapActions('foo', {
83-
g (dispatch, a: string, b: number, c: boolean): void {
84-
dispatch('g', { a, b, c })
81+
...mapActions('foo', {
82+
u (dispatch, a: string, b: number, c: boolean) {
83+
dispatch('p', { a, b, c })
8584
dispatch({
86-
type: 'g',
85+
type: 'p',
8786
a,
8887
b,
8988
c
9089
})
9190
}
9291
}),
9392

94-
mapMutations(["i"]),
95-
mapMutations({
96-
j: "j"
93+
...mapMutations(["v"]),
94+
...mapMutations({
95+
w: "w"
9796
}),
98-
mapMutations({
99-
i (commit, a: string, b: number, c: boolean): void {
100-
commit('i', { a, b, c })
97+
...mapMutations({
98+
x (commit, a: string, b: number, c: boolean) {
99+
commit('v', { a, b, c })
101100
commit({
102-
type: 'i',
101+
type: 'v',
103102
a,
104103
b,
105104
c
106105
})
107106
}
108107
}),
109-
mapMutations('foo', ["i"]),
110-
mapMutations('foo', {
111-
j: "j"
108+
...mapMutations('foo', ["y"]),
109+
...mapMutations('foo', {
110+
z: "z"
112111
}),
113-
mapMutations('foo', {
114-
i (commit, a: string, b: number, c: boolean): void {
115-
commit('i', { a, b, c })
112+
...mapMutations('foo', {
113+
aa (commit, a: string, b: number, c: boolean) {
114+
commit('v', { a, b, c })
116115
commit({
117-
type: 'i',
116+
type: 'v',
118117
a,
119118
b,
120119
c
121120
})
122121
}
123122
}),
124123

125-
helpers.mapActions(["m"]),
126-
helpers.mapActions({
127-
m: "m"
124+
...helpers.mapActions(["ab"]),
125+
...helpers.mapActions({
126+
ac: "ac"
128127
}),
129-
helpers.mapActions({
130-
m (dispatch, value: string) {
131-
dispatch('m', value)
128+
...helpers.mapActions({
129+
ad (dispatch, value: string) {
130+
dispatch('p', value)
132131
}
133132
}),
134133

135-
helpers.mapMutations(["n"]),
136-
helpers.mapMutations({
137-
n: "n"
134+
...helpers.mapMutations(["ae"]),
135+
...helpers.mapMutations({
136+
af: "af"
138137
}),
139-
helpers.mapMutations({
140-
n (commit, value: string) {
141-
commit('m', value)
138+
...helpers.mapMutations({
139+
ag (commit, value: string) {
140+
commit('v', value)
142141
}
143142
}),
144143

145-
{
146-
otherMethod () {}
147-
}
148-
)
144+
otherMethod () {}
145+
},
146+
147+
created() {
148+
// Computed
149+
this.a
150+
this.b
151+
this.c
152+
this.d
153+
this.e
154+
this.f
155+
this.g
156+
this.h
157+
this.i
158+
this.j
159+
this.k
160+
this.l
161+
this.m
162+
this.n
163+
this.o
164+
this.otherComputed
165+
166+
// Methods
167+
this.p()
168+
this.q()
169+
this.r('', 0, true)
170+
this.s()
171+
this.t()
172+
this.u('', 0, true)
173+
this.v()
174+
this.w()
175+
this.x('', 0, true)
176+
this.y()
177+
this.z()
178+
this.aa('', 0, true)
179+
this.ab()
180+
this.ac()
181+
this.ad('')
182+
this.ae()
183+
this.af()
184+
this.ag('')
185+
this.otherMethod()
186+
}
149187
});

Diff for: yarn.lock

+4-4
Original file line numberDiff line numberDiff line change
@@ -9071,10 +9071,10 @@ typedarray@^0.0.6:
90719071
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
90729072
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
90739073

9074-
typescript@^3.2.2:
9075-
version "3.2.2"
9076-
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.2.tgz#fe8101c46aa123f8353523ebdcf5730c2ae493e5"
9077-
integrity sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg==
9074+
typescript@^3.7.2:
9075+
version "3.7.2"
9076+
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.2.tgz#27e489b95fa5909445e9fef5ee48d81697ad18fb"
9077+
integrity sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==
90789078

90799079
uc.micro@^1.0.1, uc.micro@^1.0.5:
90809080
version "1.0.5"

0 commit comments

Comments
 (0)