避免将打字稿投射在开关内 [英] Avoid typescript casting inside a switch

查看:54
本文介绍了避免将打字稿投射在开关内的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

interface FooBarTypeMap {
  FOO: FooInterface;
  BAR: BarInterface;
}

type FooBarTypes = "FOO" | "BAR";

export interface FooBarAction<T extends FooBarTypes> {
  type: T;
  data: FooBarTypeMap[T];
}

const doSomthingBasedOnType = (action: FooBarAction<FooBarTypes>): void => {
  switch (action.type) {
    case "FOO":
      FooAction((action as FooBarAction<"FOO">));
  }
};

const FooAction = (action: FooBarAction<"FOO">): void => {
  //do something with action.data
};

现在我想避免进行强制转换(动作为FooBarAction< FOO>),如doSomthingBasedOnType,作为接口是否使之成为此开关内唯一可能性的定义。我可以在代码中进行某些更改以使其正常工作吗,或者这仅仅是TypeScript中的错误?

Now I would like to avoid the casting (action as FooBarAction<"FOO">) as seen in doSomthingBasedOnType, as the very definition if the interface makes this the only possibility inside this switch. Is there something I can change in my code for this to work, or is this simply a bug in TypeScript?

推荐答案

FooBarAction 转换为有区别的联合。目前,您的 FooBarAction 版本不是很严格,而 type 必须是之一 FOO | BAR data 必须是 FooBarTypeMap [FooBarTypes] = FooInterface之一。 BarInterface 两者之间没有关系。因此可以允许:

You need to transform FooBarAction into a discriminated union. At the moment your version of FooBarAction is not very strict, while type must be one of "FOO" | "BAR" and data must be one of FooBarTypeMap[FooBarTypes] = FooInterface | BarInterface there is no relation between the two. So this could be allowed:

let o : FooBarAction2<FooBarTypes> = {
  type: "BAR",
  data: {} as FooInterface
}

有区别的联合版本如下:

The discriminated union version would look like this:

export type FooBarAction = {
  type: "FOO";
  data: FooInterface;
} | {
  type: "BAR";
  data: BarInterface;
}

const doSomthingBasedOnType = (action: FooBarAction): void => {
  switch (action.type) {
    case "FOO":
      FooAction(action);
  }
};

// We use extract to get a specific type from the union
const FooAction = (action: Extract<FooBarAction, { type: "FOO" }>): void => {
  //do something with action.data
};

您还可以使用条件类型的分布行为从类型的并集创建并集:

You can also create a union from a union of types using the distributive behavior of conditional types:

interface FooInterface { foo: number}
interface BarInterface { bar: number}
interface FooBarTypeMap {
  FOO: FooInterface;
  BAR: BarInterface;
}

type FooBarTypes = "FOO" | "BAR";

export type FooBarAction<T extends FooBarTypes> = T extends any ? {
  type: T;
  data: FooBarTypeMap[T];
}: never;


const doSomthingBasedOnType = (action: FooBarAction<FooBarTypes>): void => {
  switch (action.type) {
    case "FOO":
      FooAction(action);
  }
};

const FooAction = (action: FooBarAction<"FOO">): void => {
  //do something with action.data
};

这篇关于避免将打字稿投射在开关内的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆