首页 > 解决方案 > 如何在 Typescript 中创建数组枚举?

问题描述

我有一个带有固定键的对象,我将其用作类似枚举的对象。这些值是可变长度数组。这可以按需要工作。但是,它需要在对象中的每个值上复制相同的类型断言。有没有办法一次全部输入而不是单独输入?

const Direction = 'u' | 'r' | 'd' | 'l'

const gestures = {
  newSubThought: ['r', 'd', 'r'] as Direction[],
  newThought: ['r', 'd'] as Direction[],
  clearThought: ['l', 'r'] as Direction[],
  ...
}

如果我省略as Direction[],那么值太宽,不允许我gestures.newThought作为Direction[].

The type 'string' is not assignable to type 'Direction'.

如果我将键加宽,{ [key: string]: Direction[] }那么我会丢失窄键和随之而来的自动完成功能。

标签: typescript

解决方案


There is an open issue at microsoft/TypeScript#25214 requesting the ability to annotate the type of the values of an object, while allowing the compiler to somehow infer the keys. For now there is no direct support for this; and the issue is marked as "needs proposal", meaning that it's not clear how such a feature would work. If you're really interested in seeing this happen, you could give that issue a and possibly suggest how it would work.

For now, though, you can get indirect support for this via a generic identity helper function:

const asGestures = <K extends PropertyKey>(
    gestures: { [P in K]: Direction[] }) => gestures;

Instead of annotating or asserting that each property of your object literal is a Direction[], you call asGestures() on the "plain" object literal. The compiler will constrain the type of the object to something whose values are of type Direction[], and whose keys are of type a key-like type K it infers:

const gestures = asGestures({
    newSubThought: ['r', 'd', 'r'],
    newThought: ['r', 'd'],
    clearThought: ['l', 'r']
    //...
})
/* const gestures: {
    newSubThought: Direction[];
    newThought: Direction[];
    clearThought: Direction[];
} */

Even better, if you make a mistake in your array, the compiler will notice and catch it for you:

const badGestures = asGestures({
    begoneThought: ['r', 'u', 'd', 'e'], // error!
    // --------------------------> ~~~
    // Type '"e"' is not assignable to type 'Direction'.
})

whereas type assertions using as will tend to suppress such errors (one major use of type assertions is to narrow types past what the compiler can verify):

['r', 'u', 'd', 'e'] as Direction[] // no error

Playground link to code


推荐阅读