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

Typescript从元组/数组值派生联合类型,typescript,Typescript,说我有一张单子 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

说我有一张单子
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

我想知道是否可以不使用索引映射来执行此操作。

使用数组无法执行此操作

原因是,即使将变量声明为const,数组的内容仍然可以更改,因此@jornsharpe提到这是运行时

根据您的需要,最好将
界面
keyof
一起使用:

interface X {
    a: string,
    b: string
}

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

enum X { a, b, c }
更新日期:2019年2月 在这种情况下,可以使用。这种类型的断言会使编译器推断出一个值可能的最窄类型,包括使所有内容都
为只读。应该是这样的:

const list = ['a', 'b', 'c'] as const; // TS3.4 syntax
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c';
const list = tuple('a','b','c');  // type is ['a','b','c']
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c'
type NeededUnionType = typeof list[number];  // 'a'|'b'|'c'.
这样就不需要任何类型的助手函数。祝大家好运


2018年7月更新 看起来,从TypeScript3.0开始,TypeScript3.0就可以运行了。发布后,所需的
tuple()
函数可以简洁地写成:

export type Lit = string | number | boolean | undefined | null | void | {};
export const tuple = <T extends Lit[]>(...args: T) => args;
希望这对人们有用


2017年12月更新 因为我发布了这个答案,所以我找到了一种推断元组类型的方法,如果您愿意向库中添加函数的话。查看中的函数
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']
将被推断为类型
字符串[]
,因此类型系统将忘记特定的值。您可以强制类型系统将每个值记为文字字符串:

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
这是恼人的重复,但至少在运行时不会引入无关对象

现在,您可以像这样获得您的工会:

const list = ['a', 'b', 'c'] as const; // TS3.4 syntax
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c';
const list = tuple('a','b','c');  // type is ['a','b','c']
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c'
type NeededUnionType = typeof list[number];  // 'a'|'b'|'c'.
希望对您有所帮助。

TypeScript 3.4的更新: TypeScript 3.4中将出现一种称为“const contexts”的新语法,它将提供一种更简单的解决方案,而不需要如所示的函数调用。该功能目前正在审查中

简而言之,此语法允许创建具有窄类型的不可变数组(即类型
['a'、'b'、'c']
,而不是
('a'|'b'|'c')[]
字符串[]
)。通过这种方式,我们可以轻松地从文本创建联合类型,如下所示:

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

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

(请注意“as const”将keyOne和keyTwo的类型从字符串更改为文字。)


因此,本质上,您希望动态生成类型?类型仅在编译时存在,因此您无法在运行时动态创建它们。这是一个有趣的问题。您的用例是什么?对于我经常遇到的问题,当我需要运行时检查(使用元组)和使用类型联合的编译时检查时,这是一个极好的解决方案。有人知道是否有人试图在语言中添加对隐式元组类型的支持吗?尝试了您的解决方案,但它不适用于
contxs=['a','b','c'];常量列表=元组(…xs)
不应该使用它,因为当您使用
const xs=['a','b','c']
时,编译器已经将
xs
扩展到
string[]
并完全忘记了特定的值。至少从TS3.2开始,我就无法控制这种行为(尽管将来可能会有一种
as const
表示法)。无论如何,我认为目前的答案仍然是正确的(我在那里提到,
['a','b','c']
被推断为
字符串[]
),所以我不确定你还需要什么。有人能解释一下
[number]
列表[number]
中做了什么吗?它被解析为
(列表类型)[number]
。。。不
typeof(列表[编号])
。类型
T[K]
是一个获取
T
的属性类型,其键为
K
。在
(typeof list)[number]
中,您将获得键为
number
(typeof list)
的属性类型。像
typeof list
这样的数组具有,因此它们的
number
键产生所有数字索引属性的并集。是否有方法排除某些字段?例如,如果我只需要
a
字段..您可以使用
Pick
进行选择。您好,刚刚在发布此问题后找到您的答案。如果你想回答的话,我会让你赚取一些业力;)