Распространение машинописного текста предотвращает перезапись неопределенным
При использовании оператора распространения запрещается перезаписывать ключи с новым значением undefined
Рассмотрим объектbleh1
и
const bleh1 = {
name: "ajnskdas",
foo: "oof",
bar: "something"
}
const bleh2 = {
foo: "oofElse",
bar: undefined,
booz: "chilled"
}
bleh2.bar
должен перезаписать ключbar
только если значение не неопределенно
const bleh3 = {...bleh1, ...bleh2}
// Actual
// {
// "name": "ajnskdas",
// "foo": "oofElse",
// "bar": undefined,
// "booz": "chilled"
// }
// Desired
// {
// "name": "ajnskdas",
// "foo": "oofElse",
// "bar": "something",
// "booz": "chilled"
// }
Я могу сделать это во время выполнения с помощью функцииremoveEmpty
но тип/интерфейсbleh4
не будет новых ключейbleh2
то естьbleh4.booz
не выводится машинописным текстом
function removeEmpty(obj: any) {
return Object.fromEntries(Object.entries(obj).filter(([_, v]) => v != null));
}
const bleh4 = { ...bleh1, ...removeEmpty(bleh2) }
2 ответа
основная проблема, с которой вы, похоже, сталкиваетесь, заключается в том, что ваши нетипизированные bleh1 и bleh2 несопоставимы. bleh1 говорит, что bar должен быть строкой, bleh2 говорит, что bar должен быть неопределенным.
при слиянии панель типов не может быть одновременно строковой и неопределенной, что приравнивается к типу never
однако, если вы наберете bleh1 и 2, вы можете сказать, как сопоставить схемы
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);
Как упоминалось в ответе @MikeT, при слиянии панель типов не может быть одновременно строковой и неопределенной, что приравнивается к типу никогда
Таким образом, приведенная ниже функция работает аналогично, предоставленной @xor_71 из 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(obj2)} as any
}
const bleh5 = merge(bleh1, bleh2)
removeUndefined
удаляет любые неопределенные свойства из объектаRemoveUndefinedProps
удаляет реквизит, который может быть неопределенным Таким образом, вmerge
мы можем использовать возвращаемый тип как пересечение (и)
- Уникальные ключи от obj1 (T1)
- Возможно неопределенные ключи
- Неопределенные ключи от obj2 (T2)