我有一个类型
type Foo = {
a: {
b: {
c: string[]
...rest
}
...rest
}
...rest
}
Run Code Online (Sandbox Code Playgroud)
我如何更改a.b.c为另一种类型但保留其余属性?
TypeScript 不提供任何内置的方法来执行此操作,因此如果您想要类似的东西,您必须使用映射和条件类型自己构建它。您还需要非常仔细地考虑您想要的行为,因为存在各种潜在的边缘情况,特别是对于可选/只读/等属性和函数/数组。
这是一种方法:
type _Overwrite<T, U> = U extends object ? (
{ [K in keyof T]: K extends keyof U ? _Overwrite<T[K], U[K]> : T[K] } & U
) : U
type ExpandRecursively<T> = T extends Function ? T : T extends object
? T extends infer O ? { [K in keyof O]: ExpandRecursively<O[K]> } : never
: T;
type Overwrite<T, U> = ExpandRecursively<_Overwrite<T, U>>
Run Code Online (Sandbox Code Playgroud)
该类型_Overwrite<T, U>采用一个类型T,U并递归地遍历它们的属性,如果存在冲突,则将 from 替换T为 from 。U这种类型应该可以工作,但使用交叉点来表示它,这可能会变得难看。
ExpandRecursively<T>遍历结果类型并将所有属性合并在一起的类型也是如此,所以{a: string} & {b: number}应该成为{a: string, b: number}。
并且Overwrite<T, U>只是对结果进行获取_Overwrite<T, U>和使用。ExpandRecursively<>
让我们通过一个例子来看看它的行为方式:
type Foo = {
a: {
b: {
c: string[];
d: number;
}
e: {
f: boolean;
}
};
g: {
h?: () => string;
}
}
type ReplaceFoo = Overwrite<Foo, { a: { b: { c: number } } }>;
Run Code Online (Sandbox Code Playgroud)
这产生:
/*
type ReplaceFoo = {
a: {
b: {
c: number;
d: number;
};
e: {
f: boolean;
};
};
g: {
h?: (() => string) | undefined;
};
}
*/
Run Code Online (Sandbox Code Playgroud)
这对我来说看起来很合理。T但在使用它之前,您需要非常彻底地测试这样的东西:如果和/或是U联合类型,您想做什么?T如果orU是数组或元组,你想做什么?您希望能够区分“替换a.b.c为number”和“替换a.b为{c: number}”吗?(也就是说,您是否想要选择“删除”而不是“替换”子属性?)这些问题(可能还有其他问题)的所有答案都将对您想要如何编写Overwrite<T, U>.
希望这能给您一些如何继续前进的想法。祝你好运!
| 归档时间: |
|
| 查看次数: |
1656 次 |
| 最近记录: |