【发布时间】:2019-01-17 00:03:05
【问题描述】:
我正在使用 typescript 并编写大量借鉴 redux 工作方式的代码,(action, state) => state。
非常努力地以最严格的方式使用打字稿。我的问题最好用这个例子来解释。
首先,我有一个描述动作类型的枚举:
enum Tags {
TAG_A = 'tagA',
TAG_B = 'tagB'
}
接下来我定义每种类型的唯一字段:
type Payload = {
[Tags.TAG_A]: {
foo: string;
},
[Tags.TAG_B]: {
bar: number;
}
}
现在我定义我的动作类型:
type Action<T extends Tags> = {
type: T;
id: string;
moreCommonField: boolean;
} & Payload[T];
type Actions = { [T in Tags]: Action<T> }[Tags]
现在是减速器:
type State = { somevar: string }; //doesnt matter, example
const reducer = (action: Actions, state: State): State => {
switch (action.type) {
case Tags.TAG_A:
action.foo; /* correct type, yay */
break;
case Tags.TAG_B:
action.bar; /* correct type, yay */
break;
}
return {...state};
}
到目前为止,一切都很好!
但在现实世界中,我有很多很多动作,我的switch 看起来有点丑。
所以我尝试了这个:
const minireducers: { [K in Tags]: (action: Action<K>, state: State) => State } = {
[Tags.TAG_A]: (action, state) => {
// we have correct type of action here, big benefit
return {...state};
},
[Tags.TAG_B]: (action, state) => ({...state})
}
这很好,因为大多数“微型减速器”只是单线器。这还有一个好处是迫使我不要忘记处理我以后可能添加的任何操作。
但是,当我尝试为此编写实际的减速器时:
const reducer2 = (action: Actions, state: State) => {
const minireducer = minireducers[action.type];
const newState = minireducer(action, state); //error
return newState;
}
这里的错误我很清楚,action.type 没有缩小到任何特定类型,所以minireducer 可以是很多东西,它的类型是联合,你不能调用联合。使用铸造它显然会起作用,但我想要一个不需要铸造的解决方案。甚至只是一个思想实验。
任何人对尽可能类型安全的解决方案有任何想法,这将允许我将减速器拆分为示例中的较小减速器?
您不必拘泥于我的类型定义或结构,但同样,类型安全和良好的类型推断是这里的目标。
【问题讨论】:
标签: typescript