Background:
Spread (...) and Rest (...) are among the most popular modern syntactic constructs that came from ES6. In TypeScript, they have strict typing, making the use of Spread and Rest not only convenient but also safe when type constraints are followed correctly.
Problem:
Spread and Rest operations can become a source of errors if the value types are not considered or incompatible types are mixed (for example, merging objects with incompatible properties or arrays of different types).
Solution:
In TypeScript, Spread is used to copy or merge properties of objects and elements of arrays. Rest allows gathering "remaining" elements in functions or arrays, while strict typing checks for incompatible cases, preventing errors at compile time.
Code example:
// Spread with objects const base = { a: 1, b: 2 }; const extended = { ...base, c: 3 }; // extended: { a: number; b: number; c: number } // Rest in function parameters function sum(...args: number[]): number { return args.reduce((acc, val) => acc + val, 0); } // Spread in arrays const arr = [1, 2, 3]; const newArr = [...arr, 4, 5];
Key features:
What is the difference between copying an object via Spread and assigning by reference?
Spread creates a new object with a copy of all enumerable properties, but if the object contains nested objects, they are copied by reference (shallow copy).
const base = { a: 1, nested: { x: 2 } }; const copy = { ...base }; copy.nested.x = 42; console.log(base.nested.x); // 42
Can you use Spread to copy only certain properties?
No, Spread copies all enumerable properties of an object. To select specific properties, destructuring is used:
const { a, ...rest } = { a: 1, b: 2, c: 3 }; // rest: { b: 2, c: 3 }
What happens if you merge two objects with the same properties using Spread? How does this affect typing?
Properties from the last object will override properties from the previous ones. The type of the last property will be considered final:
const a = { val: 1 }; const b = { val: 'hello' }; const merged = { ...a, ...b }; // merged: { val: string } (not number)
In the project, it was decided to merge configuration parameters using Spread. One of the objects had the property timeout: number, while the other had timeout: string. No errors were noticed until runtime when the function broke due to the wrong type.
Pros:
Cons:
Typed Spread was used to merge strict interfaces, as well as destructuring to separate unnecessary fields. The compiler immediately identified errors.
Pros:
Cons: