Распространение машинописного текста предотвращает перезапись неопределенным

При использовании оператора распространения запрещается перезаписывать ключи с новым значением 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)
Другие вопросы по тегам