TypeScript:从字符串数组定义联合类型

Posted

技术标签:

【中文标题】TypeScript:从字符串数组定义联合类型【英文标题】:TypeScript: Define a union type from an array of strings 【发布时间】:2019-02-04 17:10:23 【问题描述】:

我不可能是第一个遇到这个问题的人,但我的搜索还没有找到任何有用的线索。非常感谢一些 TypeScript 专家的建议。

假设我有一个数组:

const fruits = ["Apple", "Orange", "Pear"];

我想定义一个对象,将每个水果映射到一些有趣的事实:

interface Facts 
    color: string,
    typicalWeight: number


const fruitFacts:  [key: members of fruits]: Facts  = 
    "Apple":  color: "green", typicalWeight: 150 
    //

[key: members of fruits] 部分我该怎么做?

奖励:我如何强制我的 fruitFacts 对象也耗尽从数组派生的所有键,以便在上面的示例中指定 Apples、Oranges 和 Pears 的事实。

【问题讨论】:

你知道编译时的确切字符串吗?如果不是,则不能定义这样的类型。 假设我愿意。我可以避免复制它们吗?即避免做type FruitName = "Apple" | "Orange"; const fruitNames : FruitName[] = ["Apple", "Orange"]; ***.com/questions/45251664/… 【参考方案1】:

TypeScript 3.4 添加了const assertions,允许将其写为:

const fruits = ["Apple", "Orange", "Pear"] as const;
type Fruits = typeof fruits[number]; // "Apple" | "Orange" | "Pear"

使用as const,TypeScript 将上述fruits 的类型推断为readonly["Apple", "Orange", "Pear"]。以前,它会将其推断为string[],从而阻止typeof fruits[number] 生成所需的联合类型。

【讨论】:

为什么这不起作用?:const fruitTypes = ["Apple", "Orange", "Pear"];const fruits = fruitTypes as const; @techguy2000 我认为这是因为您可以拥有:const fruitTypes = ["Apple", "Orange", "Pear"]; fruitTypes.push("Kiwi"); const fruits = fruitTypes as const;。在这种情况下,TS 没有可靠的方法知道该类型现在应该是 ["Apple", "Orange", "Pear", "Kiwi"];,因此允许在初始定义之后将其标记为 const 是一种不安全的模式。 当我冻结数组时它仍然不起作用:const fruitTypes = Object.freeze(["Apple", "Orange", "Pear"]); 我真的希望这个的一些变化会起作用...... @techguy2000 可能值得在 TS 问题跟踪器中作为功能建议打开,将这种情况输入为readonly["Apple", "Orange", "Pear"] 而不是readonly string[] 似乎是合理的。 @Batman 写 typeof fruits[number] 告诉 Typescript 我们感兴趣的是存储在 fruits 数组中的值的类型。因为它是一个数组,所以这些值由number 索引。用简单的英语来说,就像我们在询问 TypeScript“对于从 fruits 请求的任何给定整数索引,将返回的值的可能类型是什么?”【参考方案2】:

可以做到,但首先你需要一个额外的函数来帮助推断数组元素的字符串文字类型。默认情况下,Typescript 会为数组推断 string[],即使它是一个常量。在我们拥有一个字符串字面量类型的数组后,我们可以使用类型查询来获取所需的类型

function stringLiteralArray<T extends string>(a: T[]) 
    return a;


const fruits = stringLiteralArray(["Apple", "Orange", "Pear"]);
type Fruits = typeof fruits[number]

从 3.4 开始,您还可以使用 const 类型断言来代替 stringLiteralArray 函数:

const fruits = ["Apple", "Orange", "Pear"] as const;
type Fruits = typeof fruits[number]

【讨论】:

typeof fruits[number] 的这个特定标注是我所需要的——它使它成为一个字符串联合而不是只读字符串[]

以上是关于TypeScript:从字符串数组定义联合类型的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript:来自字符串联合文字数组类型,不允许数组中存在任何冗余值

TypeScript数组到字符串文字类型

TypeScript 基础类型

TypeScript类型

TypeScript中的类型化数组到文字类型

TypeScript:推断嵌套联合类型的类型