Skapa ett nytt objekt i TypeScript baserat på ett befintligt objekt


I TypeScript har jag ett baskobjekt som en mall och jag vill duplicera det objektet och ändra bara en egenskap på liknande sätt som nedan:

interface user {
    name: string, 
    jobTitle: string
}

const employee: user = {name: 'Liane', jobTitle: 'Web Dev'}

const newEmployee1 = employee;
newEmployee1.name = 'James';
const newEmployee2 = employee;
newEmployee2.name = 'John';

Men när jag tittar på resultaten i konsolen är varje anställds namn 'John' som visas nedan:

{name: 'John', jobTitle: 'Web Dev'}
{name: 'John', jobTitle: 'Web Dev'}
{name: 'John', jobTitle: 'Web Dev'} 

Jag förstår att detta beror på objektreferenser, men jag vill inte referera till basanställningen utan jag vill klona den som ett eget objekt oberoende av de andra användarna. Så när jag loggar objekten i konsolen kommer jag att få:

{name: 'Liane', jobTitle: 'Web Dev'}
{name: 'James', jobTitle: 'Web Dev'}
{name: 'John', jobTitle: 'Web Dev'}

Finns det något sätt för mig att göra detta?

Svar #1

2025 Uppdatering

Det finns massor av alternativ här (mer än de jag har listat).
De flesta av dem är mycket läsbara; utöver det har varje sitt eget för- och nackdelar när det gäller prestanda, tillgänglighet och funktionalitet.
Jag kommer att gå igenom varje som jag listar nedan:

  1. Spreadoperator (...)
  2. Object.assign
  3. Strukturerad klon (structuredClone

Spreadoperator (...)

Spridningssyntaxen är förmodligen den mest mångsidiga syntaxen av alla alternativ, detta kan användas på Funktioner, Arrayer och Objekt:

// Functions
myFunction(a, ...iterableObj, b)
// Arrays
[1, ...iterableObj, '4', 'five', 6]
// Objects
{ ...obj, key: 'value' }

(Källa: Docs)
Detta är en ganska lättläst syntax men kan vara långsammare jämfört med andra metoder - detta svar diskuterar det mer.
Caniuse

Object.assign

Till skillnad från spridning är Object.assign fokuserad på objekt ({}) endast, men det innehåller en varning kring djupt kopiering (där det rekommenderar structuredClone).
Du kan också använda det för att kopiera flera objekt samtidigt:

const o1 = { a: 1, b: 1, c: 1 };
const o2 = { b: 2, c: 2 };
const o3 = { c: 3 };

const obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

(Källa: Docs)
Caniuse

Strukturerad klon (structuredClone)

Jag lärde mig nyligen om denna metod från detta svar; structuredClone verkar vara en utmärkt metod för att göra djupt kopior av objekt.
Observera att det finns något olika förväntningar när man använder metoden för något som ett ArrayBuffer, se Överföring av ett objekt

Vi kan använda bufferten i det klonade objektet, men om vi försöker använda den ursprungliga bufferten kommer vi att få ett undantag.

// Create an ArrayBuffer with a size in bytes
const buffer1 = new ArrayBuffer(16);

const object1 = {
  buffer: buffer1,
};

// Clone the object containing the buffer, and transfer it
const object2 = structuredClone(object1, { transfer: [buffer1] });

// Create an array from the cloned buffer
const int32View2 = new Int32Array(object2.buffer);
int32View2[0] = 42;
console.log(int32View2[0]);

// Creating an array from the original buffer throws a TypeError
const int32View1 = new Int32Array(object1.buffer);

(Källa: Docs)
Caniuse

Originalt svar

Om du vill klona ett befintligt objekt skulle jag rekommendera "spread-operatorn"

// interface user {
//     name: string, 
//     jobTitle: string
// }

// const employee: user = {name: 'Liane', jobTitle: 'Web Dev'}
const employee = {name: 'Liane', jobTitle: 'Web Dev'}

const newEmployee1 = {
  ...employee,
  name: 'James'
};

const newEmployee2 = {
  ...employee,
  name: 'John'
};

console.log(employee)
console.log(newEmployee1)
console.log(newEmployee2)

Svar #2

Det enklaste sättet skulle vara att använda antingen spridningsoperatorn:

const newEmployee1 = {
  ...employee,
  name: 'James',
};
const newEmployee2 = {
  ...employee,
  name: 'John',
};

Eller med en Object.assign():

const newEmployee1 = Object.assign({}, employee);
newEmployee1.name = 'James';

const newEmployee2 = Object.assign({}, employee);
newEmployee2.name = 'John';

Tänk på att ingen av dessa är en djup kopia, och icke-primära värden delar samma referens.