Как скопировать из одного объекта в другой только нужные свойства?
У меня есть два интерфейса:
interface IPerson {
name: string;
age: number;
}
и
interface IEmployee {
name: string;
age: number;
salary: number;
}
и нужно скопировать данные из объекта типа IEmployee в объект типа IPerson. Но если это сделать так:
const person: IPerson = { ...employee };
то в объекте person окажется и свойство salary, что меня не устраивает.
С Object.assign ровно такая же ситуация.
Как мне скопировать только те свойства, которые есть в типе объекта-приёмника?
UPDATE: Забыл упомянуть, что решения, основанные на конкретных именах свойств, типа
const { name, age } = employee;
const person = { name, age };
не устраивают, т.к. в реальном приложении в этих интерфейсах много свойств, плюс в процессе разработки их состав часто меняется. Поэтому нужно универсальное решение.
Ответы (3 шт):
Можно просто заранее создать "пустой" экземпляр класса и вместо деструктуризации пройтись по его полям и если в объекте employee есть эти поля, то забрать их. Если 100% всегда в employee будут все поля интерфейса IPerson, то провекру в цикле можно опустить
Код:
interface IPerson {
name: string;
age: number;
}
interface IEmployee extends IPerson {
salary: number;
}
const PersonTemplate: IPerson = {
name: '',
age: 0
}
const employee: IEmployee = {name: 'Name', age: 18, salary: 1000};
const person: IPerson = {} as IPerson;
const copyField = < T extends {} > (k: keyof T, target: T, source: T) => {
target[k] = source[k];
}
for (const key in PersonTemplate) {
const keyName = key as keyof IPerson;
if (keyName in employee) copyField(keyName, person, employee);
}
console.log(person);
Доработанная до максимальной универсальности идея от @Mr. Man: одна универсальная функция + по одной функции на каждый тип, в который нужно преобразовывать:
// universal function
function createFrom<T extends {}>(source: T, template: T) {
const target = {} as T;
for (const key in template) {
const keyName = key as keyof T;
target[keyName] = source[keyName];
}
return target;
}
// types
interface IPerson {
name: string;
age: number;
}
function createPersonFrom(source: IPerson) {
const template: IPerson = {
name: '',
age: 0
}
return createFrom(source, template);
}
interface IEmployee {
name: string;
age: number;
salary: number;
}
// work
const employee: IEmployee = { name: 'Name', age: 18, salary: 1000 };
const person = createPersonFrom(employee);
console.log(person);
const employee: IEployee = ???;
const {salary, ...person} = employee;
переменная person внезапно удовлетворяет интерфейсу IPerson