在 TypeScript 中切换特定类型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/50774790/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 05:28:31  来源:igfitidea点击:

Switch for specific type in TypeScript

typescript

提问by Vladyslav Zavalykhatko

I have an interface Action:

我有一个界面Action

interface Action {}

And an implementation of this ActionSpecificAction:

以及这个的实现ActionSpecificAction

class SpecificAction implements Action {
   payload?: Any
}

Is it possible in TS to construct a switch operator, like this:

是否可以在 TS 中构造一个 switch 运算符,如下所示:

let action: Action
switch (action) {
   case SpecificAction: //it works
       console.log(action.payload) // it doesn't 
}

Is it possible in that case to know, that action is already of SpecificActiontype?

在这种情况下,是否有可能知道该操作已经属于SpecificAction类型?

采纳答案by Dan Dohotaru

for the time being it looks like there are a few options, all of them with some drawbacks

目前看起来有几个选择,所有这些都有一些缺点

  • discriminated unions docsstackblitz, but you'll need a dedicated property as discriminator
interface Action {}

class SpecificAction implements Action {
  kind: "specific";
  payload?: any;
}

class ToggleAction implements Action {
  kind: "toggle";
  toggle: boolean;
}

let action: SpecificAction | ToggleAction;
switch (action.kind) {
  case "specific":
    console.log(action.payload) // it works 
    break;
  case "toggle":
    console.log(action.toggle) // it works 
    break;        
}
  • User-Defined Type Guards docsstackblitz, but you'll need if statements instead of switch
  • User-Defined Type Guards docs stackblitz,但你需要 if 语句而不是 switch
interface Action {}

class SpecificAction implements Action {
  payload?: any;
}

class ToggleAction implements Action {
  toggle: boolean;
}

let isSpecific = (p: any): p is SpecificAction => !!p.payload
let isToggle = (p: any): p is ToggleAction => !!p.toggle

let action: Action;
if (isSpecific(action)) {
  console.log(action.payload) // it works 
} else if (isToggle(action)) {
  console.log(action.toggle) // it works 
}
  • constructor property githubstackblitz, but you'll need to cast to desired type for the time being
interface Action { }

class SpecificAction implements Action {
  payload?: any;
}

class ToggleAction implements Action {
  toggle: boolean;
}

switch (action.constructor) {
  case SpecificAction:
    console.log((<SpecificAction>action).payload) // it kinda works 
    break;
  case ToggleAction:
    console.log((<ToggleAction>action).toggle) // it kinda works 
    break;
  }

回答by speedsheaf

I assume the desire for using switchstatements for type-checking is readability. Firstly, the first solution gives all native typescript solutions, however the drawbacks are quite annoying, and the solution I will provide is better. Instead of using switches, use labeled statements. For example, consider the following example:

我认为使用switch语句进行类型检查的愿望是可读性。首先,第一个解决方案提供了所有原生打字稿解决方案,但是缺点很烦人,我将提供的解决方案更好。不要使用switches,而是使用带标签的 statements。例如,请考虑以下示例:

const t = [];
typecheck: {
    if (t instanceof Array) {
        console.log("true")
        break typecheck;
    }
    if (t instanceof Object) {
        console.log("shouldn't appear")
        break typecheck;
    }
}

It works just as well as switch, but with the added benefit that typescript can specialize the types.

它与 switch 一样有效,但还有一个额外的好处,即打字稿可以专门化类型。

回答by pushkin

You'd be better off using an ifstatement with typeguards.

你最好使用if带有 typeguards的语句。

let action: Action = ...;
if (isSpecificAction(action)) {
    console.log(action.payload);
}

function isSpecificAction(action: any): action is SpecificAction {
    return action.payload;
}

At the end of the day, TypeScript is still JavaScripty, and the switchstatement gets transpiled to a regular JS switch:

归根结底,TypeScript 仍然是 JavaScripty,并且该switch语句被转换为常规 JS switch

A switch statement first evaluates its expression. It then looks for the first case clause whose expression evaluates to the same value as the result of the input expression (using the strict comparison, ===)

switch 语句首先评估它的表达式。然后查找第一个 case 子句,其表达式的计算结果与输入表达式的结果相同(使用严格比较,===)

So in your case:

所以在你的情况下:

interface Action {}
class SpecificAction implements Action {
   payload?: any
}

let action: Action
switch (action) {
   case SpecificAction: //it works
       console.log(action.payload) // it doesn't 
}

actionwould be evaluated and compared with the classSpecificAction. Presumably, actionis an instanceof SpecificAction(or some object that implements the Actioninterface).

action将被评估并与班级进行比较SpecificAction。据推测,action是一个实例SpecificAction(或一些对象实现该Action接口)。

With a switch, you could do this:

使用switch,你可以这样做:

let a: Action = new SpecificAction();
let b: Action = a;

switch (a) {
    case b:
        console.log("Worked");
}

The expression ais evaluated and compared to the expression b(and a === b, so we hit the console.log), but that's obviously not what you're looking for.

对表达式a进行评估并与表达式进行比较b(并且a === b,所以我们点击了console.log),但这显然不是您要查找的内容。

If you want to check if an instance is of a particular type (re: class), then you should use a type guard. A switch/caseis the wrong construct.

如果你想检查一个实例是否属于特定类型(re: class),那么你应该使用类型保护。Aswitch/case是错误的构造。



Alternatively, why not use instanceof?

或者,为什么不使用instanceof

interface Action { };
class SpecificAction implements Action {}
class NotSpecificAction implements Action {}

let action: Action = new SpecificAction();
console.log(action instanceof SpecificAction); // true
console.log(action instanceof NotSpecificAction); // false