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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45251664/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:44:59  来源:igfitidea点击:

Typescript derive union type from tuple/array values

typescript

提问by WHITECOLOR

Say I have list const list = ['a', 'b', 'c']

说我有清单 const list = ['a', 'b', 'c']

Is it possible to derive from this value union type that is 'a' | 'b' | 'c'?

是否可以从这个值联合类型派生'a' | 'b' | 'c'

I want this because I want to define type which allows only values from static array, and also need to enumerate these values at runtime, so I use array.

我想要这个是因为我想定义只允许来自静态数组的值的类型,并且还需要在运行时枚举这些值,所以我使用数组。

Example how it can be implemented with an indexed object:

示例如何使用索引对象实现它:

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

I wonder if it is possible to do it without using an indexed map.

我想知道是否可以在不使用索引地图的情况下做到这一点。

回答by jcalz

UPDATE Feb 2019

2019 年 2 月更新

In TypeScript 3.4, which should be released in March 2019it will be possible to tell the compiler to infer the type of a tuple of literals as a tuple of literals, instead of as, say, string[], by using the as constsyntax. This type of assertion causes the compiler to infer the narrowest type possible for a value, including making everything readonly. It should look like this:

应于 2019 年 3 月发布的 TypeScript 3.4 中,可以告诉编译器将文字元组的类型推断为文字元组,而不是string[]使用as const语法. 这种类型的断言会导致编译器为一个值推断出可能的最窄类型,包括使所有的readonly. 它应该是这样的:

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

This will obviate the need for a helper function of any kind. Good luck again to all!

这将消除对任何类型的辅助函数的需要。再次祝大家好运!



UPDATE July 2018

2018 年 7 月更新

It looks like, starting with TypeScript 3.0, it will be possible for TypeScript to automatically infer tuple types. Once is released, the tuple()function you need can be succinctly written as:

看起来,从 TypeScript 3.0 开始,TypeScript 可以自动推断元组类型。一旦被释放,tuple()你需要的函数可以简洁地写成:

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

And then you can use it like this:

然后你可以像这样使用它:

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

Hope that works for people!

希望对人有用!



UPDATE December 2017

2017 年 12 月更新

Since I posted this answer, I found a way to infer tuple types if you're willing to add a function to your library. Check out the function tuple()in tuple.ts. Using it, you are able to write the following and not repeat yourself:

自从我发布了这个答案,如果您愿意向库中添加一个函数,我就找到了一种推断元组类型的方法。退房的功能tuple()tuple.ts。使用它,您可以编写以下内容而不是重复自己:

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

Good luck!

祝你好运!



ORIGINAL July 2017

原件 2017 年 7 月

One problem is the literal ['a','b','c']will be inferred as type string[], so the type system will forget about the specific values. You can force the type system to remember each value as a literal string:

一个问题是文字['a','b','c']将被推断为 type string[],因此类型系统会忘记特定的值。您可以强制类型系统将每个值作为文字字符串记住:

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

Or, maybe better, interpret the list as a tuple type:

或者,也许更好,将列表解释为元组类型:

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

This is annoying repetition, but at least it doesn't introduce an extraneous object at runtime.

这是烦人的重复,但至少它不会在运行时引入无关对象。

Now you can get your union like this:

现在你可以像这样得到你的工会:

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

Hope that helps.

希望有帮助。

回答by ggradnig

Update for TypeScript 3.4:

TypeScript 3.4 更新:

A new syntax called "const contexts"that will arrive in TypeScript 3.4 will allow for an even simpler solution that doesn't require a function call as demonstrated. This feature is currently in review as seen in this PR.

将在 TypeScript 3.4 中出现的一种名为“const contexts”的新语法将允许一个更简单的解决方案,不需要像演示的那样调用函数。如本 PR 中所示,此功能目前正在审核

In short, this syntax allows for the creation of immutable arrays that have a narrow type (i.e. the type ['a', 'b', 'c']instead of ('a' | 'b' | 'c')[]or string[]). This way, we can create union types from literals as easy as shown below:

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

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

In alternative syntax:

在替代语法中:

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

回答by unional

It is not possible to do this with Array.

使用 Array 无法做到这一点。

The reason is, even if you declare the variable as const, the content of an array can still change, thus @jonrsharpe mention this is runtime.

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

Given what you want, it may be better to use interfacewith keyof:

鉴于您想要什么,使用interfacewith可能更好keyof

interface X {
    a: string,
    b: string
}

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

Or enum:

enum

enum X { a, b, c }