在没有枚举开销的情况下获取数组值的字符串文字类型的方法

Vla*_*kov 6 typescript

在我的项目中,我需要许多字符串文字类型和各种类型的任务(如类型保护)的允许值数组。

这就是我们所拥有的:

type Animal = 'cat' | 'dog' | 'rabbit' | 'snake'
const animals: Animal[] = ['cat', 'dog', 'rabbit', 'snake']
Run Code Online (Sandbox Code Playgroud)

它可以工作,但是需要在源代码中多次列出键。

另一种方法是使用“ 获取字符串文字类型值的数组”中建议的枚举,但由于枚举的已编译代码大于数组,因此在运行时会产生开销。

我找到了另一种没有运行时开销的方法,但是我不确定它将来是否会起作用,因为它可能是一个错误。

const notWidened = <T extends string>(val: T[]) => val

const animals = notWidened(['cat', 'dog', 'rabbit', 'snake'])
type Animal = typeof animals[0]
Run Code Online (Sandbox Code Playgroud)

因此,问题是使用此代码段是否安全,或者将来会中断。有没有更好的方法来获取文字字符串类型和数组而不重复。

jca*_*alz 6

我目前找不到这方面的好文档,但您的notWidened()函数运行良好并且不是错误。如果您将类型参数限制为string或 的子类型,TypeScript 将推断泛型类型变量的字符串文字string。因此<T extends keyof U><T extends string><T extends 'a'|'b'>等将推断 的字符串文字T。(如果您有类似的约束,您也可以推断numberboolean文字T)。

所以据我所知,你的代码很好;我唯一可以做的不同的是

type Animal = (typeof animals)[number]
Run Code Online (Sandbox Code Playgroud)

代替

type Animal = typeof animals[0]
Run Code Online (Sandbox Code Playgroud)

因为 的0第 th 元素animals实际上是'cat',即使您已经告诉 TypeScript 它是'cat'|'dog'|...。不过你的还好。

正如我上面评论的,如果您希望 TypeScript 被视为animals一个元组,其中animals[0]is of type 'cat'animals[1]is of type等,您可以使用类似于tuple.ts中的'dog'函数的内容 (2018 年 7 月更新,从 TypeScript 3.0 开始编译器将能够自动推断元组类型,因此函数可以更简洁):tuple()

export type Lit = string | number | boolean | undefined | null | void | {};
export const tuple = <T extends Lit[]>(...args: T) => args;

const animals = tuple('cat', 'dog', 'rabbit', 'snake');
type Animal = (typeof animals)[number];  // union type
Run Code Online (Sandbox Code Playgroud)

这可能对你有用。


TL;DR:你的代码没问题。

希望有帮助;祝你好运!