If you're looking to achieve something similar in TypeScript, you won't find a built-in solution. You'll need to create your own implementation using mapped types and conditional types. It's crucial to carefully consider the specific behavior you desire as there are various potential edge cases to handle, especially with optional, readonly properties, arrays, and functions.
Here is one approach you can take:
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>>
The type _Overwrite<T, U>
takes two types, T
and U
, recursively traverses through their properties, replacing matching ones from T
with those from U
when conflicts arise. While this type should suffice, be aware that it utilizes intersection types, which may lead to complexity.
Therefore, ExpandRecursively<T>
merges all properties within the resulting type, ensuring that {a: string} & {b: number}
becomes {a: string, b: number}
.
In turn, Overwrite<T, U>
applies ExpandRecursively<>
on the outcome of _Overwrite<T, U>
.
Let's examine how this behaves with an example:
type Foo = {
a: {
b: {
c: string[];
d: number;
}
e: {
f: boolean;
}
};
g: {
h?: () => string;
}
}
type ReplaceFoo = Overwrite<Foo, { a: { b: { c: number } } }>;
This results in:
/*
type ReplaceFoo = {
a: {
b: {
c: number;
d: number;
};
e: {
f: boolean;
};
};
g: {
h?: (() => string) | undefined;
};
}
*/
The output seems reasonable, but thorough testing is recommended before implementation. Consider scenarios where T
or U
might be union types, arrays, or tuples. Reflect on whether you want to differentiate between "replace a.b.c
with number
" and "replace a.b
with {c: number}
".(Do you wish to "erase" or "overwrite" subproperties?) All these considerations will influence how you implement Overwrite<T, U>
.
This guidance should provide clarity on moving forward. Best of luck!
Playground Link to code