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

Ara*_*edi 17 typescript

我不能成为遇到这个问题的第一个人,但我的搜索还没有发现任何有用的线索.非常感谢一些专家的TypeScript建议.

说我有一个数组:

const fruits = ["Apple", "Orange", "Pear"];
Run Code Online (Sandbox Code Playgroud)

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

interface Facts {
    color: string,
    typicalWeight: number
}

const fruitFacts: { [key: members of fruits]: Facts } = {
    "Apple": { color: "green", typicalWeight: 150 }
    //
}
Run Code Online (Sandbox Code Playgroud)

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

额外:我如何强制我的fruitFacts对象耗尽从数组派生的所有键,以便它在上面的例子中指定苹果,橘子和梨的事实.

Ben*_*pan 29

TypeScript 3.4添加了const断言,可以将其编写为:

const fruits = ["Apple", "Orange", "Pear"] as const;
type Fruits = typeof fruits[number]; // "Apple" | "Orange" | "Pear"
Run Code Online (Sandbox Code Playgroud)

使用as constTypeScript可以将fruits上述类型推断为readonly["Apple", "Orange", "Pear"]。以前,它将推断为string[],从而typeof fruits[number]无法生成所需的联合类型。

  • @techguy2000我认为这是因为你可以有: `const FruitTypes = ["Apple", "Orange", "Pear"]; FruitTypes.push("猕猴桃"); const Fruits = FruitTypes as const;`。在这种情况下,TS 没有可靠的方法知道类型现在应该是 `["Apple", "Orange", "Pear", "Kiwi"];`,因此允许将其标记为 `const` 是一种不安全的模式稍后在初始定义之后。 (2认同)
  • 当我冻结数组时它仍然不起作用: `const FruitTypes = Object.freeze(["Apple", "Orange", "Pear"]);` 我真的希望它的一些变体能够起作用...... (2认同)
  • @techguy2000 这可能值得在 TS 问题跟踪器中作为功能建议开放,看起来确实可以合理地将这种情况键入为“readonly["Apple", "Orange", "Pear"]`而不是`只读字符串[]`。 (2认同)
  • @Batman 写的 `typeoffruits[number]` 告诉 Typescript 我们感兴趣的是存储在 `fruits` 数组中的值的类型。因为它是一个数组,所以这些值由“number”索引。用简单的英语来说,就像我们在询问 TypeScript“对于从‘fruits’请求的任何给定整数索引,将返回的值的可能类型是什么?” (2认同)

Tit*_*mir 15

它可以完成,但首先你需要一个额外的函数来帮助推断数组元素的字符串文字类型.默认情况下string[],即使数组是常量,也会推断出数组.在我们有一个字符串文字类型数组之后,我们可以使用类型查询来获得所需的类型

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

const fruits = stringLiteralArray(["Apple", "Orange", "Pear"]);
type Fruits = typeof fruits[number]
Run Code Online (Sandbox Code Playgroud)

  • “typeoffruits[number]”的特定标注正是我所需要的 - 它使其成为字符串联合而不是只读字符串[] (2认同)