假设我有一个常量且不可变的字符串列表a
const a = ['b', 'c', 'd']
我想创建一个如下所示的类型A:
type A = 'b' | 'c' | 'd'
我的问题是:如何自动从列表A
创建类型a
?
另一种方式对我也有用:如何在类型a
A
答案 0 :(得分:1)
是,您可以这样做。唯一的障碍是,如果你写
const a = ['b','c','d'];
// inferred as string[]
然后a
将被推断为string[]
,因此当您尝试推导时,文字值'a'
,'b'
和'c'
会被遗忘A
。您始终可以明确注释a
的类型:
const a: ['b','c','d'] = ['b','c','d'];
type A = typeof a[number];
//type A = "b" | "c" | "d"
但现在你正在重复自己,你正试图避免。有一个解决方案:
在an answer to another question中,我推荐了一个辅助函数(tuple.ts中的tuple()
)来推断元组类型。
const a = tuple('b','c','d');
//inferred as type ["b", "c", "d"]
type A = typeof a[number];
//type A = "b" | "c" | "d"
如果你不关心它是一个元组,你可以编写一个简单的数组推理辅助函数:
function inferLiteralArray<T extends string>(...arr: T[]): T[] {
return arr;
}
const a = inferLiteralArray("b", "c", "d");
//inferred as type ("b" | "c" | "d")[]
type A = typeof a[number];
//type A = "b" | "c" | "d"
无论哪种方式都有效,而且你不需要重复自己。希望有所帮助;祝你好运!
@fritz_da_silva said:
太棒了,它工作得很整齐! a [number]语法对我来说就像黑魔法。你能详细说明它的工作原理吗?
不确定。语法应该像这样解释(为了清楚起见,请参阅我添加的括号):
type A = (typeof a)[number];
typeof a
部分正在使用typeof
type query operator获取a
的类型,(tuple()
示例)为["b", "c", "d"]
。
然后我使用indexed access operator。如果您的键之一<{1}}类型T
(因此它应该扩展K
;您可以使用{{1}等字符串文字或者像keyof T
这样的数字文字或这些的联合),然后"length"
是该密钥可访问的属性的类型。对于arraylike类型0
,类型T[K]
获取该数组类型的元素类型。在元组示例中,这结果是一个联合,因为有多个类型A
的键具有不同的属性类型。 (当您使用索引访问运算符时,A[number]
应等于number
)。观察:
T[K1|K2]
这有意义吗?
答案 1 :(得分:0)
由于数组是在运行时创建的,因此无法执行您想要执行的操作,并且编译器无法确定对数组的更改。因此,它无法强制执行类型系统。
例如,请考虑以下事项:
const array = [ "Bob", "James", "Dan" ];
let value: *A key of array*
setTimeout(() => {
value = "James";
}, 1000);
array.splice(1, 1);
上述情况会发生什么?在调用value = "James
时,"James"
已从数组中删除,因此应该抛出错误!但这在运行时发生,因此编译器无法向您发出警告。
解决方法是使用以下构造声明一个类型,但不能修改它:
type MyType = "Bob" | "James" | "Dan"
let value: MyType = "Dan";
value = "Steven" // <- Compiler error!
编辑:saravana在评论中快速总结。