switch case语句中的Typescript类型安全性

问题描述 投票:5回答:3

我正在使用Redux,我正在尝试使我的减速器类型安全。我在ngrx-store / example应用程序中找到了一些代码示例,他们完全成功地做到了这一点。 (https://github.com/ngrx/example-app/blob/master/src/app/actions/book.ts

在将这个集成到我自己的项目中时,我发现了一些奇怪的东西,我无法解释。检查以下代码示例(内联注释):

// 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
    }
}

如果我将FIRST和SECOND属性的定义替换为以下内容,它确实有效。

export function type<T>(label: T | ''): T {
    return <T>label;
}


const FIRST = type("FIRST");
const SECOND = type("SECOND");

据我所知,type函数只将字符串强制转换为字符串。为什么代码在调用type函数时有效,但在立即声明字符串时却没有?

这是一个typescript playground example,你可以在里面或外面评论定义(首先是工作版本)。

typescript typescript2.0
3个回答
2
投票

这是因为TSC编译器无法区分这两个值:

const FIRST = "FIRST";
const SECOND = "SECOND";

它都是string类型,因此TSC不知道哪个属于什么。你必须给它一个类型,这就是你用你的type函数进行投射所做的。

但如果按如下方式编写它会更容易:

const FIRST: "FIRST" = "FIRST";
const SECOND: "SECOND" = "SECOND";

Typescript playground


0
投票

它只适用于const,而不是正则表达式,没有变量。

switch(variable_expression) { 
   case constant1: { 
      //code; 
      break; 
   } 
   case constant2: { 
      //code; 
      break; 
   } 
   default: { 
      //code; 
      break; 
   } 
}

-1
投票

我会使用as运算符:

let temp = (action as FirstAction).payload.id;

其他一些想法: - 如果你已经拥有所有行动类实施的Actions,你真的需要Action吗? - 将每个案例的减速器提取到一个函数中可能有助于可读性和单元测试。 - 请记住,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;
    // ...
}

// ...
© www.soinside.com 2019 - 2024. All rights reserved.