[英]Typescript type safety in switch case statements
I'm working with Redux and I'm trying to make my reducers type safe. 我正在使用Redux,我正在尝试使我的减速器类型安全。 I found some code example from the ngrx-store/example app where they perfectly succeed in doing this.
我在ngrx-store / example应用程序中找到了一些代码示例,他们完全成功地做到了这一点。 ( https://github.com/ngrx/example-app/blob/master/src/app/actions/book.ts )
( https://github.com/ngrx/example-app/blob/master/src/app/actions/book.ts )
While integrating this in my own project, I noticed something strange, which I cannot explain. 在将这个集成到我自己的项目中时,我发现了一些奇怪的东西,我无法解释。 Check the following code sample (some comments inline):
检查以下代码示例(内联注释):
// Action has a type and payload property
interface Action {
type: string;
payload?: any;
}
// Here I declare the action types as plain strings
const FIRST = "FIRST";
const SECOND = "SECOND";
// I create classes for every action with there respective types
class FirstAction implements Action {
public type = FIRST;
payload: { id: number };
public constructor(id: number) {
this.payload = { id };
}
}
class SecondAction implements Action {
public type = SECOND;
public constructor() { }
}
// Create a union type
type Actions = FirstAction | SecondAction;
// Use the union type as type parameter in my function
function test(action: Actions): void {
switch (action.type) {
case FIRST:
// compiler will complain it cannot find the payload
// property on Actions
let temp = action.payload.id;
case SECOND:
// empty
default:
//empty
}
}
If I replace the definition of the FIRST and SECOND properties into the following, it does work. 如果我将FIRST和SECOND属性的定义替换为以下内容,它确实有效。
export function type<T>(label: T | ''): T {
return <T>label;
}
const FIRST = type("FIRST");
const SECOND = type("SECOND");
As far as I can see, the type function only casts the string back to a string. 据我所知,type函数只将字符串强制转换为字符串。 Why does the code work with calling the
type
function but not when declaring the strings immediately? 为什么代码在调用
type
函数时有效,但在立即声明字符串时却没有?
Here's a typescript playground example where you can just comment the definitons in or out (first with the working version). 这是一个打字稿操场示例 ,您可以在其中注释定义(首先是工作版本)。
It's because the TSC compiler cannot distinct the 2 values: 这是因为TSC编译器无法区分这两个值:
const FIRST = "FIRST";
const SECOND = "SECOND";
It's both of type string
, thus TSC doesn't know which belongs to what. 它都是
string
类型,因此TSC不知道哪个属于什么。 You have to give it a type, and that's what you're doing by casting it with your type
function. 你必须给它一个类型,这就是你用你的
type
函数强制它所做的。
But it's easier if you write it as follows: 但如果按如下方式编写它会更容易:
const FIRST: "FIRST" = "FIRST";
const SECOND: "SECOND" = "SECOND";
It works just with const, not regular expressions, no variables. 它只适用于const,而不是正则表达式,没有变量。
switch(variable_expression) {
case constant1: {
//code;
break;
}
case constant2: {
//code;
break;
}
default: {
//code;
break;
}
}
I would use the as
operator: 我会使用
as
运算符:
let temp = (action as FirstAction).payload.id;
Some other thoughts: 其他一些想法:
- Do you really need Actions
if you already have Action
that all your action classes implement? - 如果您已经拥有所有操作类都实现的
Action
,那么您真的需要Actions
吗?
- Extracting the reducer of each case into a function may help readability and unit testing. - 将每个案例的减速器提取到一个函数中可能有助于可读性和单元测试。
- Remember that reducers take state and action, and return state (I understand you just simplified your example). - 请记住,reducer采取状态和操作,并返回状态(我知道你只是简化了你的例子)。
function test(state: State, action: Action): State {
switch (action.type) {
case FIRST:
return handleFirst(state, action as FirstAction);
case SECOND:
return handleSecond(state, action as SecondAction);
default:
return state;
}
}
function handleFirst(state: State, action: FirstAction): State {
let temp = action.payload.id;
// ...
}
// ...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.