说我有名单
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
我想知道是否可以在不使用索引地图的情况下进行此操作。
答案 0 :(得分:39)
在TypeScript 3.4, which should be released in March 2019中,可以告诉编译器将文字元组的类型推断为文字元组,而不是像string[]
那样,使用as const
syntax。这种类型的断言使编译器推断出一个值可能的最窄类型,包括创建所有readonly
。它应该是这样的:
const list = ['a', 'b', 'c'] as const; // TS3.4 syntax
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c';
这将消除对任何类型的辅助函数的需要。祝大家好运!
看起来,从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'
希望对人有用!
由于我发布了这个答案,如果你愿意为你的库添加一个函数,我找到了一种推断元组类型的方法。查看tuple.ts中的tuple()
函数。使用它,您可以编写以下内容而不是重复:
const list = tuple('a','b','c'); // type is ['a','b','c']
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c'
祝你好运!
一个问题是文字['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'.
希望有所帮助。
答案 1 :(得分:6)
一种称为“ const contexts” 的新语法将出现在TypeScript 3.4中,它将提供一个甚至更简单的解决方案,不需要演示的函数调用。 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]
答案 2 :(得分:2)
无法使用Array执行此操作。
原因是,即使你将变量声明为const,数组的内容仍然可以改变,因此@jonrsharpe提到这是运行时。
根据您的需要,将import { Observable } from 'rxjs/Observable';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
export class ServiceMock {
public http: Http;
url: string;
getGoogle(): Observable<any> {
return this.http.get('./data.mock').map((res) => {
res.json();
});
}
}
与export class Data {
name: string = 'Aditya';
profession: string = 'Developer';
}
一起使用可能更好:
interface
或keyof
:
interface X {
a: string,
b: string
}
type Y = keyof X // Y: 'a' | 'b'
答案 3 :(得分:0)
如果使用对象来存储“常量”,则这是实现相同思想的一种方式:
(请注意'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];