我有以下对象
[{
"key": "a1",
...
}, {
"key": "a2",
...
}, ...]
可以从这个对象中提取联合类型"a1" | "a2" | ...
吗?我知道可以使用tuple API从['a1', 'a2', ...]
中提取它,这是在TypeScript String Union to String Array中介绍的,但是我不能为对象数组解决这个问题
发布于 2019-01-02 16:57:04
基本上,您只需要对数组元素的"key"
属性执行lookup,其中可以通过查找数组的number
属性来找到数组的元素。不幸的是,困难的部分是让它显示为任何东西而不是"string"
。
const val = [{ key: "a1" }, { key: "a2" }]; // Array<{key: string}>
type ValueAtKey = (typeof val)[number]["key"]; // string
这是因为编译器推断val
只是一个具有string
值的对象数组。编译器使用一些启发式方法来确定when to widen literals,在上面的例子中,确切的字符串文字被扩展为string
。
TS3.4+的更新
对于TypeScript 3.4,让编译器推断对象/数组文字的最具体类型的推荐方法是使用const
assertion
const val = [{ key: "a1" }, { key: "a2" }] as const;
// const val: readonly [{ readonly key: "a1"; }, { readonly key: "a2"; }]
type ValueAtKey = (typeof val)[number]["key"]; // "a1" | "a2"
原始版本TS3.4之前的答案
在TS3.4之前,你必须做一些其他的事情。提示编译器像"a1"
这样的值应该缩小到"a1"
而不是扩大到string
的一种方法是使值与类型constrained匹配到string
(或包含它的联合)。下面是我有时用来做这件事的助手函数:
type Narrowable =
string | number | boolean | symbol | object |
null | undefined | void | ((...args: any[]) => any) | {};
const literally = <T extends { [k: string]: V | T } | Array<{ [k: string]: V | T }>,
V extends Narrowable>(t: T) => t;
literally()
函数只返回它的参数,但是类型往往更窄。是的,它很丑陋。
现在您可以执行以下操作:
const val = literally([{ key: "a1" }, { key: "a2" }]); // Array<{key: "a1"}|{key: "a2"}>
type ValueAtKey = (typeof val)[number]["key"]; // "a1" | "a2"
val
对象在运行时是相同的,但TypeScript编译器现在将其视为{key: "a1"}
或{key: "a2"}
类型的值数组。然后,为ValueAtKey
完成的查找就会给出您正在寻找的联合类型。
(请注意,我假设您并不关心这里val
的顺序。也就是说,您可以将其视为数组而不是tuple。由于联合类型"a1" | "a2"
没有固有的顺序,因此数组应该足够了。)
https://stackoverflow.com/questions/54009764
复制相似问题