typescript - 如何使用联合类型深度展平 Typescript 接口并将完整的对象路径保留在键中
问题描述
假设我有以下界面:
interface Foo {
foo: string
bar?: number
nested: {
foo: string,
deeplyNested: {
bar?: number
}
}
union: string | {
foo: string,
bar?: number
}
}
现在我需要一种类型来将此接口转换为扁平版本,其中键中包含完整路径名,如下所示:
interface FooFlattened {
foo: string
bar?: number
"nested.foo": string
"nested.deeplyNested.bar"?: number
// if union is a string:
union: string
// if union is an object:
"union.foo": string
"union.bar"?: number
}
该类型应该适用于任何级别的嵌套和任何数量的联合成员。
我已经在这里找到了一个相关的问题,但这只是一个非常基本的接口,没有联合或可选参数。
解决方案
首先,我们可以创建一个类型,其中包含对象的有效虚线路径的联合。值得庆幸的是,我们已经有了一个很好的答案,在这里提供了一种方法。
使用该Leaves
答案中的类型,我们可以构建您的路径联合:
type DottedFooPaths = Leaves<Foo>;
// type DottedFooPaths = "foo" | "bar" | "union" | "nested.foo" | "nested.deeplyNested.bar" | "union.foo" | "union.bar"
现在我们需要使用这些路径作为键创建一个新对象,并将每个路径与原始对象中它对应的值类型相关联。为了实现这一点,我们可以反向执行点路径转换,并使用它递归地索引到我们的原始类型:
type FollowPath<T, P> = P extends `${infer U}.${infer R}` ? U extends keyof T ? FollowPath<T[U], R> : never : P extends keyof T ? T[P] : never;
// For example, this might produce:
type FooDotBar = FollowPath<Foo, "bar"> // number | undefined
然后,如果我们构造一个类型,其中每个键都是 的成员之一Leaves<Foo>
,我们可以使用它FollowPath
来提取相应的值类型:
type FlattenedFoo = {
[K in Leaves<Foo>]: FollowPath<Foo, K>
}
// Produces:
// type FlattenedFoo = {
// foo: string;
// bar: number | undefined;
// union: string | {
// foo: string;
// bar?: number | undefined;
// };
// "nested.foo": string;
// "nested.deeplyNested.bar": number | undefined;
// "union.foo": never;
// "union.bar": never;
// }
这几乎是您想要的结果,但它丢失了键上的可选修饰符;尽管我不确定是否有办法保留可选修饰符。
推荐阅读
- angular - 无法删除 Firebase 数据库的节点
- python - Google Sheets API v4 删除不清除行
- python - 如何在 tkinter 中对列进行网格化?
- ruby - Windows gem 安装错误:extconf.rb:301:in `assert_has_dev_libs!': UTF-8 中的无效字节序列(ArgumentError)
- kotlin - 在 Kotlin 中递归构建数据类
- node.js - IBM Cloud Functions Calling API with authentication / node.js
- python - 如何在 Python 中编写正确的 if 语句?
- python - discord python - 计算一周的消息并保存它们
- python - TFIDFVectorizer Pipeline 上具有不同 ngram 范围的 Word 和 Char ngram
- c++ - c ++同一类中的类实例,使用构造函数