【问题标题】:Discriminated Union types cases from array来自数组的可区分联合类型案例
【发布时间】:2021-08-19 16:49:40
【问题描述】:

我可以从一个字符串创建一个联合类型,一个字符串数组,如下所示:

const types = [
  'AAA',
  'BBB'
] as const

type myType = typeof types[number]

myType 现在是'AAA' | 'BBB'

现在我想像这样创建一个有区别的联合:

type typeAAA = {
  type: 'AAA'
  // further properties
}

type typeBBB = {
  type: 'BBB'
  // further properties
}

type typeAorB = typeAAA | typeBBB

我想确定,我只能将 myType 用于有区别的联合 - 这可能吗?

更新: 我想确保typeAorB 的情况与types 的值同步。现在我可以将任意字符串值分配给typeAAAtypetypeBBB

我不想使用接口或类。

我这样做是因为我想要的是验证数据的能力,并且我想验证 typeAorBoneOf<myType>(伪代码)。

【问题讨论】:

  • “我想确认一下,我只能将myType 用于有区别的联合...” 你能澄清一下你的意思吗?听起来您正在尝试阻止某些事情,您能举个例子说明您要阻止的事情吗?
  • 我想确保typeAorB 的大小写与types 的值同步。现在我可以将任何字符串值分配给typeAAAtypetypeBBB
  • 因此,例如,如果您使用type: "CCC" 创建了一个typeCCC,但在types 中没有"CCC",则希望阻止您在typeAorB 中包含typeCCC ?
  • 是的,这正是我想要的。

标签: typescript


【解决方案1】:

看起来您实际上想要映射您的联合类型以创建可区分的联合,并能够将自定义属性附加到联合的各个成员。

如果情况确实如此,您可以使用分布条件类型来很好地分布在您的联合类型上。

类似

const types = [
  'AAA',
  'BBB'
] as const

type myType = typeof types[number]

type Distribute<U> = U extends any
  ? U extends "AAA"
    ? { type: U, prop1: number }
    : U extends "BBB"
      ? { type: U, prop2: boolean }
      : never
  : never


type Discriminated = Distribute<myType>

这会产生与这个形状的联合

{
    type: "AAA";
    prop1: number;
} | {
    type: "BBB";
    prop2: boolean;
}

我假设工会成员的其他属性需要不同,否则我认为有歧视的工会没有任何意义。请注意,因此,如果您向myType 添加任何新成员,您必须在Distribute 中适当地处理它。

【讨论】:

  • If 我正确理解了问题的最终目标(大“如果”),这并不妨碍在分发中添加 type: "CCC" 分支在types 中没有"CCC"(尽管Discriminated 的类型不包括该分支)。 Example 但至少,再一次,它没有出现在 Discriminated 中。
  • (我几乎肯定天真的solution 也有同样的问题。)
  • 我明白了,我想我当时还没有完全理解这个问题。希望OP可以澄清
  • 我不知道,你的Discriminated 看起来很像我想要的typeAorB,如果我们能在定义点出现错误就好了。如果您尝试使用第三种类型,它仍然会出错。这可能是我们能做的最好的了。
  • 对。最终,编译器在哪里吐出错误几乎没有什么区别,只要它阻止你做一些不正确的事情。您可能会争辩说,想要typeAorB to be in sync with the values of types 并不是您真正想要的,您真正想要的是编译器在您做错事时通知您。
【解决方案2】:

如果您尝试使用第三种类型,我能得到的最接近的结果会给您一个错误,但是将它添加到typeAorB 时不会出现错误(bugs' solution 有同样的问题,但很多比下面更酷)。我希望我能在那里得到一个错误。

我添加了一个基本类型:

type baseTypeAorB = {
    type: myType;
}

并将其包含在typeAorB:

type typeAorB = baseTypeAorB & (typeAAA | typeBBB)

现在,如果您尝试向其中添加 typeCCC,您(很遗憾)不会收到错误消息:

type typeCCC = {
  type: 'CCC'
  // further properties
}

type typeAorB = baseTypeAorB & (typeAAA | typeBBB | typeCCC) // No error (sadly)

但生成的typeAorB 没有其中有typeCCC;如果你将它悬停在操场上,你会发现它仍然只是:

type typeAorB = (baseTypeAorB & typeAAA) | (baseTypeAorB & typeBBB)

baseTypeAorB 基本上阻止了 typeCCC 的类型。因此,如果您尝试使用它,就好像它包含 typeCCC 一样,您会收到错误:

let x: typeAorB = {
  type: "CCC" // <=== But there is an error here (yay!)
}

Playground link

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-06
    • 2020-02-16
    • 2017-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多