Частичное обновление объекта с помощью typescirpt

#typescript

Вопрос:

Чего я пытаюсь достичь, так это создать служебную функцию, которая исключает экземпляр и объект и обновляет экземпляр с помощью предоставленных значений полей ввода. Вот функция полезности:

 function updateEntity<T, K extends keyof T>(
    entity: T,
    updateInput: { [key in K]: T[K] },
  ): void {
    return Object.keys(updateInput).forEach((key) => {
      entity[key as K] = updateInput[key as K];
    });
}
 

и вот у меня есть экземпляр и интерфейс обновления:

 class Animal {
  name: string = 'no name';
  isMale: boolean = false;
}

type Input = Partial<{
  name: string;
}>;

const input: Input = {
  name: 'str'
};

const cat = new Animal();

updateEntity(cat, input); // input is an error
 

Я получаю следующую ошибку:

 Argument of type 'Partial<{ name: string; }>' is not assignable to parameter of type '{ name: string; }'.
  Types of property 'name' are incompatible.
    Type 'string | undefined' is not assignable to type 'string'.
      Type 'undefined' is not assignable to type 'string'.(2345)
 

Я не думаю, что полностью понимаю сообщение об ошибке. Мое намерение состояло в том, чтобы частично обновить исходный экземпляр с помощью предоставленных входных данных.

Входные данные должны быть подмножеством исходного экземпляра (без дополнительных полей).

Вот ссылка на игровую площадку: ссылка

Что я упускаю?

Комментарии:

1. Не связано, но ваша частичная часть кажется немного излишней, name?: string вы просто сделали бы то же самое, вы имели в виду type Input = Partial<Animal> , или если бы вам нужно было только имя type Input = Partial<Pick<Animal, 'name'>> , иначе вы могли бы определить имя как строку в одном месте и логическое значение в другом, кажется гораздо более чистым, чтобы тип имени определялся только один раз.

2. Это всего лишь простой пример, хотя я мог бы сделать Partial<Animal> то, что я хочу, чтобы у меня был выделенный интерфейс/тип

Ответ №1:

Используйте ненулевое утверждение. Когда вы наведете курсор на updateInput параметр, его тип будет { [key in K]?: T[K] | undefined } таким, потому что поля, которые отсутствуют, будут такими undefined . TypeScript по-прежнему считает, что updateInput[key] это может быть undefined скорее, чем T[K] , но мы почти уверены, что updateInput[key] это может быть только тип T[K] .

 function updateEntity<T, K extends keyof T>(
  entity: T,
  updateInput: { [key in K]?: T[K] },
): void {
  for (const key in updateInput) {
    entity[key] = updateInput[key]!;
  }
}
 

Комментарии:

1. Это позволит полям за пределами T. См. cide здесь: typescriptlang.org/play? #код/…