typescript 从元组/数组值派生联合类型

w8f9ii69  于 2022-12-27  发布在  TypeScript
关注(0)|答案(5)|浏览(210)

假设我有一个数组:

const list = ['a', 'b', 'c']

是否可以从这个值联合类型派生'a' | 'b' | 'c'
我想这样做是因为我想定义只允许静态数组中的值的类型,并且还需要在运行时枚举这些值,所以我使用数组。
示例如何使用索引对象实现它:

const indexed = {a: null, b: null, c: null}
const list = Object.keys(index)
type NeededUnionType = keyof typeof indexed

不使用索引Map是否可以做到这一点?

pbwdgjma

pbwdgjma1#

更新日期:2019年2月

在2019年3月发布的TypeScript 3.4中,通过使用as const syntax,可以告诉编译器将常量元组 * 的类型推断为常量元组 *,而不是string[]。这种Assert类型会导致编译器推断值的最窄类型。包括把所有东西都变成readonly。它应该看起来像这样:

const list = ['a', 'b', 'c'] as const; // TS3.4 syntax
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c';

这将消除对任何形式的助手功能的需要。再次祝大家好运!

更新日期:2018年7月

看起来,从TypeScript 3.0开始,TypeScript将有可能实现automatically infer tuple types。一旦发布,您需要的tuple()函数可以简洁地写为:

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

然后你可以这样使用它:

const list = tuple('a','b','c');  // type is ['a','b','c']
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c'

希望这对人们有用!
2017年12月###更新
自从我发布了这个答案之后,我发现了一种方法来推断元组类型,如果你想在你的库中添加一个函数的话。看看tuple.ts中的函数tuple()。使用它,你可以写下面的代码,而不用重复自己的代码:

const list = tuple('a','b','c');  // type is ['a','b','c']
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c'

祝你好运!

原创2017年7月

一个问题是字面量['a','b','c']将被推断为类型string[],因此类型系统将忘记具体的值,您可以强制类型系统将每个值作为字面量字符串来记忆:

const list = ['a' as 'a','b' as 'b','c' as 'c']; // infers as ('a'|'b'|'c')[]

或者,更好的方法是将列表解释为元组类型:

const list: ['a','b','c'] = ['a','b','c']; // tuple

这是令人讨厌的重复,但至少它不会在运行时引入无关的对象。
现在你可以这样得到你的工会:

type NeededUnionType = typeof list[number];  // 'a'|'b'|'c'.
thtygnil

thtygnil2#

针对TypeScript 3.4的更新:

TypeScript3.4中的新语法**“constcontexts”**将提供一个更简单的解决方案,不需要函数调用。该特性目前正在as seen in this PR中审查。
简而言之,这种语法允许创建具有窄类型的不可变数组(即['a', 'b', 'c']类型,而不是('a' | 'b' | 'c')[]string[]类型)。这样,我们可以很容易地从字面量创建联合类型,如下所示:

const MY_VALUES = <const> ['a', 'b', 'c']
type MyType = typeof MY_VALUES[number]

在替代语法中:

const MY_VALUES = ['a', 'b', 'c'] as const
type MyType = typeof MY_VALUES[number]
lf5gs5x2

lf5gs5x23#

我猜你在2019年3月之后就开始使用TypeScript了。(现在是2021年11月)
我只是用一个可导出的实用函数扩展了the top answer

// Your handmade utils' library file
export type UnionOfArrayElements<ARR_T extends Readonly<unknown[]>> = ARR_T[number];
// Usage
const a = ["hi", "bye", 3, false] as const;
type ta = UnionOfArrayElements<typeof a>; // false | "hi" | "bye" | 3

const b = [4, 5, 6];
type tb = UnionOfArrayElements<typeof b>; // number
tyg4sfes

tyg4sfes4#

使用Array无法执行此操作。
原因是,即使你声明变量为const,数组的内容仍然可以改变,因此@jonrsharpe提到这是运行时。
考虑到您的需要,最好将interfacekeyof一起使用:

interface X {
    a: string,
    b: string
}

type Y = keyof X  // Y: 'a' | 'b'

enum

enum X { a, b, c }
yduiuuwa

yduiuuwa5#

如果使用一个对象来存储“常量”,这是一种实现相同思想的方法:

  • (注意,“as const”将keyOne和keyTwo的类型从字符串更改为文字。)*
const configObj = {
  keyOne: 'literalTypeValueOne' as const,
  keyTwo: 'literalTypeValueTwo' as const,
};

const typeValues = [configObj.keyOne, configObj.keyTwo] as const;
type MyType = typeof typeValues[number];

相关问题