我可以根据对象中的其他属性推断类型吗?

时间:2021-01-08 14:41:55

标签: typescript

我注意到我的代码中有一个模式,我觉得有一个更好的解决方案。

假设我有这些基本实体

type User = {
  id: string,
}

type Company = {
  id: number,
}

enum Member {
 Company = "Company",
 Member = "Member",
}

现在我经常像这样传递有效载荷

type Payload = {
  type: Member,
  payload: Company["id"][] | User["id"][] // string[] | number[]
}

现在的问题是,如果我检查了类型,我可以推断出负载的类型吗?现在我必须声明类型。

if (payload.type === Member.Company)
   result = (payload.payload as number[]).map(etc) // have to declare type of array, how to infer?

1 个答案:

答案 0 :(得分:2)

为了使其正常工作,您希望 Payload 类型为 discriminated union。现在,您的 Payload 是非联合类型,其每个属性都是联合;因此,它可以接受您不想要的值,例如 typeCompanypayload 具有来自 idUser。工会应该被推到最高级别,在那里你说明所涉及的关系:

type Payload =
  { type: Member.Company, payload: Company["id"][] } |
  { type: Member.Member, payload: User["id"][] };

现在我们有了一个顶级联合,并且由于每个成员的 type 属性都是一个单元类型(只有一个可能的值),编译器将理解检查 type 来区分联合:

  if (payload.type === Member.Company) {
    payload.payload.map(x => x + 1); // okay
  } else {
    payload.payload.map(x => x.toUpperCase()); // okay
  }

如果你有很多枚举成员,你可以考虑制作一个映射接口来表示每个枚举成员与其指向的对象之间的关系,并用它来计算Payload,这样你就不必写了组成一个拥有几乎相同 {type: Member.XXX, payload: YYY["id"][]} 成员的大联合:

interface MemberMapping {
  [Member.Company]: Company;
  [Member.Member]: User;
}

type Payload = {
  [K in Member]: { type: K, payload: MemberMapping[K]["id"][] }
}[Member];
/* type Payload = {
    type: Member.Company;
    payload: number[];
} | {
    type: Member.Member;
    payload: string[];
} */

Playground link to code