When using spread operator, prevent overwriting keys with new value undefined
Consider an object bleh1
and bleh2
const bleh1 = {
name: "ajnskdas",
foo: "oof",
bar: "something"
}
const bleh2 = {
foo: "oofElse",
bar: undefined,
booz: "chilled"
}
bleh2.bar
should overwrite key bar
only if value is not undefined
const bleh3 = {...bleh1, ...bleh2}
// Actual
// {
// "name": "ajnskdas",
// "foo": "oofElse",
// "bar": undefined,
// "booz": "chilled"
// }
// Desired
// {
// "name": "ajnskdas",
// "foo": "oofElse",
// "bar": "something",
// "booz": "chilled"
// }
I can do it during runtime with function removeEmpty
but type/interface of bleh4
wont have new keys of bleh2
ie bleh4.booz
is not inferred by typescript
function removeEmpty(obj: any) {
return Object.fromEntries(Object.entries(obj).filter(([_, v]) => v != null));
}
const bleh4 = { ...bleh1, ...removeEmpty(bleh2) }
the main issue you seem to be having is that your untyped bleh1 and bleh2 are incomparable bleh1 says that bar must be a string, bleh2 says bar must be undefined
when merging the types bar can't be both string and undefined at the same time, which equates to the type never
however if you type bleh1 and 2 then you can tell it how to match the schemas
function merge<T1, T2>(a: T1, b: T2): Partial<T1 & T2> {
const rtn: Partial<T1 & T2> = { ...a };
for (const [k, v] of Object.entries(b)) {
if (v) rtn[k as keyof T2] = v;
}
return rtn;
}
const bleh3 = merge(
{
name: 'ajnskdas',
foo: 'oof',
bar: 'something',
} as {
foo: string;
bar: string | undefined;
name: string;
},
{
foo: 'oofElse',
bar: undefined,
booz: 'chilled',
} as {
foo: string;
bar: string | undefined;
booz: string;
}
);
console.log(bleh3);
As mentioned in the answer by @MikeT, when merging the types bar can't be both string and undefined at the same time, which equates to the type never
Thus the function below works similar, provided by @xor_71 from Typescript Discord
function removeUndefined(obj: any) {
return Object.fromEntries(Object.entries(obj).filter(([_, v]) => v != undefined));
}
type RemoveUndefinedProps<T extends Record<string, unknown>> = {[key in keyof T]-?: Exclude<T[key], undefined>}
const merge = <T1 extends Record<string, unknown>, T2 extends Record<string, unknown>>(obj1: T1, obj2: T2):
Omit<T1, keyof T2>
& {[key in keyof T2 & keyof T1]-?: undefined extends T2[key] ? Exclude<T2[key], undefined> | T1[key] : T2[key]}
& Omit<RemoveUndefinedProps<T2>, keyof T1> => {
return {...obj1, ...removeUndefined(bleh2)} as any
}
const bleh5 = merge(bleh1, bleh2)
removeUndefined
removes any undefined properties from an object RemoveUndefinedProps
removes props that can be undefined Thus in the merge
function we can use the return type as an intersection (and) of
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.