我有类型
type Foo = {
a: {
b: {
c: string[]
...rest
}
...rest
}
...rest
}
如何将a.b.c
更改为其他类型,但保留其余属性?
答案 0 :(得分:1)
TypeScript不提供任何内置方法来执行此操作,因此,如果您想要类似的内容,则必须使用mapped和conditional类型自己构建。您还需要非常小心地仔细考虑所需的行为,因为存在各种潜在的极端情况,尤其是对于可选/只读/等属性和函数/数组。
这是一种实现方法:
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>>
类型_Overwrite<T, U>
接受类型T
和U
并递归地遍历它们的属性,如果存在,将T
中的那些替换为U
中的那些是一个冲突。这种类型应该可以使用,但是使用intersections来表示它,这可能很难看。
因此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 } } }>;
这将产生:
/*
type ReplaceFoo = {
a: {
b: {
c: number;
d: number;
};
e: {
f: boolean;
};
};
g: {
h?: (() => string) | undefined;
};
}
*/
对我来说哪个看起来合理。但是,您需要在使用前进行彻底的测试:如果T
和/或U
为union types,您想做什么?如果T
或U
是数组或tuple,该怎么办?您是否希望能够将“ a.b.c
替换为number
”和“ a.b
替换为{c: number}
”之间进行区分? (也就是说,您是否希望选择“擦除”而不是“替换”子属性?)所有这些问题(可能还有其他问题)的答案都会与您如何编写{{ 1}}。
希望可以为您提供一些前进的思路。祝你好运!