使用枚举作为字典键

时间:2019-02-05 20:13:26

标签: typescript dictionary enums

我正在尝试为给定的枚举创建有保证的查找。与之类似,对于枚举的每个键,在查找中应该只存在一个值。我想通过类型系统保证这一点,以便在枚举扩展时不会忘记更新查找。我尝试过:

type EnumDictionary<T, U> = {
    [K in keyof T]: U;
};

enum Direction {
    Up,
    Down,
}

const lookup: EnumDictionary<Direction, number> = {
    [Direction.Up]: 1,
    [Direction.Down]: -1,
};

但是我遇到了这个奇怪的错误:

  

键入'{[Direction.Up]:数字; [Direction.Down]:数字; }”不能分配给“方向”类型。

这对我来说似乎很奇怪,因为这是说lookup的类型应该是Direction而不是EnumDictionary<Direction, number>。我可以通过将lookup声明更改为:

来确认这一点。
const lookup: EnumDictionary<Direction, number> = Direction.Up;

没有错误。

如何为枚举创建查找类型,以确保枚举的每个值都将导致另一个不同类型的值?

TypeScript版本:3.2.1

3 个答案:

答案 0 :(得分:5)

您可以执行以下操作:

type EnumDictionary<T extends string | symbol | number, U> = {
    [K in T]: U;
};

enum Direction {
    Up,
    Down,
}

const a: EnumDictionary<Direction, number> = {
    [Direction.Up]: 1,
    [Direction.Down]: -1
};

我感到惊讶,直到我意识到枚举可以被视为specialised union type

  

另一个变化是枚举类型本身有效地变成了   每个枚举成员的并集。虽然我们尚未讨论联合类型,   您需要知道的是,对于联合枚举,类型系统为   能够利用这样的事实:它知道一组确切的值   存在于枚举本身。

以这种方式定义的EnumDictionary基本上是内置的Record类型:

type Record<K extends string, T> = {
    [P in K]: T;
}

答案 1 :(得分:1)

鉴于您的用例,我正在分享一个我经常用来解决此类问题的策略,尽管它不是严格意义上的枚举方法。

首先我创建一个只读 as const 数据结构 - 通常一个数组就足够了...

const SIMPLES = [
    "Love",
    "Hate",
    "Indifference",
    "JellyBabies"
  ] as const;

...然后我可以简单地在数字上使用映射类型来获取条目...

  type SimpleCase = (typeof SIMPLES)[number];

enter image description here

我喜欢这种方法的两个方面......

  • 运行时访问
  • 可扩展性。

运行时访问

通常您可以编写程序以确保不会遗漏任何内容,而不仅仅是将问题视为红线或编译时错误...

const caseLabels = CASES.map((item) => item.toUpperCase());

可扩展性

遍历您想出的任何 as const 数据结构是微不足道的,这意味着您不必处理不必要的类型系统来定义例如与类型分开映射类型化定义。但是,您可以在需要时购买使用它,因为 as const 方案允许 Typescript 编译器访问“检查”您选择的类型,您可以从那里使用映射类型。

const COMPLEXES = {
  "Love":{letters:4},
  "Hate":"corrodes",
  "Indifference":() => console.log,
  "JellyBabies": [3,4,5]
} as const;

type Complex = keyof typeof COMPLEXES;
type ComplexRecord = typeof COMPLEXES[keyof typeof COMPLEXES];

show keys extracted as types show values extracted as types

当然,一旦您的静态记录条目可以作为一种类型进行寻址,您就可以从它们组合其他数据结构,这些数据结构本身将对您的原始数据结构进行穷举。

  type ComplexProjection = {
    [K in Complex]:boolean;
  }

demonstrate exhaustiveness in projected type

出于这个原因,我从未使用过 Enum,因为我发现没有 Enum 的语言已经足够强大。

请参阅 this Typescript Playground 以试验上述类型所展示的方法。

答案 2 :(得分:0)

enum FunStuff {
  PARTY = "party",
  CAKE = "cake",
  PIZZA = "pizza",
}

因此,如果您需要所有Enum值

type MapOfFunStuff = {
  counts: { [key in FunStuff] : number };
}

然后,如果您只想在枚举中使用值,但可以添加任意数量的值,则可以添加?

type MapOfFunStuff = {
  counts: { [key in FunStuff]? : number };
}