【发布时间】:2020-12-08 17:54:00
【问题描述】:
从这些类型开始:
type A = { commonKey: { a: string }[] };
type B = { commonKey: { b: number }[] };
是否可以获得以下类型?不知道commonKey。
type C = { commonKey: { a: string, b: number }[] }
我的尝试是type C = A & B,但生成的类型 C 不可用:
const c: C = // ...
c.commonKey.map(x => x.a) // `a` exists here, but not `b`
我需要一种通用的方法来做到这一点,独立于commonKey:
type ArrayContent = A['commonKey'][number] & B['commonKey'][number]
type C = { commonKey: ArrayContent[] };
上下文
使用 TypeScript 4.1 模板文字类型和递归条件类型,我正在尝试改进 Elasticsearch 查询的类型。 我们为 Elasticsearch 集群中的文档生成了一个类型,如下所示:
interface Post {
id: string;
title: string | null;
author: {
name: string;
};
comments: {
id: string;
message: string;
}[];
}
使用 Elasticsearch 在运行时,您可以通过路径限制检索的字段。如果键是数组或普通对象,则语法没有区别。
const sourceFields = ['id', 'author.name', 'comments.message'];
我正在尝试创建一个新类型,使用文档类型和源字段将构建实际检索到的类型。这是我目前所拥有的:
type ExtractPath<Obj, Path extends string> =
Obj extends undefined ? ExtractPath<NonNullable<Obj>, Path> | undefined :
Obj extends null ? ExtractPath<NonNullable<Obj>, Path> | null :
Obj extends any[] ? ExtractPath<Obj[number], Path>[] :
Path extends `${infer FirstKey}.${infer OtherPath}`
? (FirstKey extends keyof Obj
? { [k in FirstKey]: ExtractPath<Obj[FirstKey], OtherPath> }
: never)
: Path extends keyof Obj
? { [K in Path]: Obj[Path] }
: never;
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
type Distribute<Obj, Fields> = Fields extends string ? ExtractPath<Obj, Fields> : never;
export type PartialObjectFromSourceFields<Obj, Fields> = UnionToIntersection<Distribute<Obj, Fields>>
用法:
// Reusing the `Post` interface described above
const sourceFields = ['id', 'author.name', 'comments.message'] as const;
type ActualPost = PartialObjectFromSourceFields<Post, typeof sourceFields[number]>;
/* `ActualPost` is equivalent to:
{
id: string;
author: {
name: string;
};
comments: {
message: string;
}[];
} */
即使键可以是undefined 或null,或者用于嵌套对象,它也能正常工作。但是,一旦我想检索数组中的两个字段 (['comments.id', 'comments.message']),我就会遇到上述问题。我只能访问第一个定义的键。有什么想法吗?
【问题讨论】:
-
其实我把数组的交集作为TypeScript的功能请求提交:github.com/microsoft/TypeScript/issues/41874
-
很抱歉,但这不是最好的主意。实际上,您正在为数组元素的交集提出一个边缘情况。这不是理想的行为
-
我认为我有一个有效的用例,而且我认为这种行为很奇怪,只考虑交集的第一个元素。但是,是的,也许我的用法并不常见。
标签: typescript typescript-generics