【问题标题】:Creating a Typescript `Record<>` type with numeric enums使用数字枚举创建 Typescript `Record<>` 类型
【发布时间】:2018-05-26 08:37:44
【问题描述】:

在 Typescript 中,可以使用字符串枚举创建记录类型:

enum AxisLabel { X = "X", Y = "Y" }
export const labelLookup: Record<AxisLabel, string> = {
  [AxisLabel.X]: "X axis",
  [AxisLabel.Y]: "Y Axis"
};

我需要创建一个类似于上述对象的Record 对象,但我不希望使用字符串枚举

当我尝试这样的事情时:

enum AxisLabel { X, Y }
export const labelLookup: Record<AxisLabel, string> = {
  [AxisLabel.X]: "X axis",
  [AxisLabel.Y]: "Y Axis"
};

Typescript 产生以下错误:

Type 'AxisLabel' does not satisfy the constraint 'string'.

可以用数字和字符串作为成员名来创建JS对象。

我希望在 Typescript 中做同样的事情,但不使用不安全的强制转换或类型转换。 如何在 Typescript 中创建数字枚举 Record 类型而不使用字符串枚举、any 或类型转换?

【问题讨论】:

    标签: typescript enums


    【解决方案1】:

    更新:TypeScript 2.9 added support 用于 numbersymbol 作为有效键类型,因此上面的代码不再给出错误,并且不再需要此答案,只要您使用的是 TypeScript 2.9或以上。

    对于 TypeScript 2.8 及以下版本:


    JavaScript 中的对象键,不管你信不信,总是strings(好吧,或者Symbols),即使是数组也是如此。当您将非字符串值作为键传递时,它首先被强制转换为字符串。但当然人们希望数字键有意义,尤其是对于数组。 TypeScript 反映了这种不一致的哲学:通常你只能指定字符串值的键(例如在mapped types 中,如Record&lt;K,V&gt;)。当这些情况相互作用时,您会感到奇怪。

    这是我有时会做的一件事:使用以下元组类型显式表示从数字到字符串的强制转换:

    export type NumericStrings = ["0","1","2","3","4","5","6","7","8","9","10"] // etc
    

    请注意,您可以根据需要对其进行扩展。然后,您可以使用lookup types 将数字类型转换为对应的字符串,以便在映射类型中使用。像这样:

    export enum AxisLabel { X, Y }
    
    // note the key is NumericStrings[AxisLabel], not AxisLabel    
    export const labelLookup: Record<NumericStrings[AxisLabel], string> = {
      [AxisLabel.X]: "X axis",
      [AxisLabel.Y]: "Y Axis"
    };
    

    这可以正常工作。如果您检查labelLookup 的类型,它会显示为Record&lt;"0" | "1", string&gt;。当您尝试索引到 labelLookup 时,会发生以下最常见的事情:

    labelLookup[AxisLabel.X]; // okay
    labelLookup[0]; // okay
    labelLookup["0"]; // also okay
    
    labelLookup[10]; // error
    labelLookup.X; //error
    

    希望有所帮助;祝你好运!

    【讨论】:

      【解决方案2】:

      record 的定义非常明确,key 必须可以赋值给 string,所以没有办法将 Record 与数字一起使用,更一般的映射类型中的 key must 是一个字符串。

      您可以使用常规索引签名,但不能将索引签名限制为字符串或数字以外的任何内容(根据language spec),这意味着任何数字都有效,而不仅仅是枚举值:

      export const labelLookup: { [index: number]: string } = {
          [AxisLabel.X]: "X axis",
          [AxisLabel.Y]: "Y Axis",
          [3] = "" // Also works but you don't want that
      };
      

      【讨论】:

        猜你喜欢
        • 2019-10-14
        • 2018-10-18
        • 2012-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-09-23
        • 2021-03-17
        相关资源
        最近更新 更多