Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to type-safely use object spread in TypeScript to update an immutable object

Tags:

typescript

Object spread is widely used to update old object in functional style like so:

let o1 = { x: 5, y: 6 };
let o2 = { ...o1, y: 10 };
alert(JSON.stringify(o2));

In new TypeScript 2.1 we now have object spread implemented but unlike simple object literal it allows to have unknown properties:

interface Point { x: number, y: number }

let o1: Point = { x: 5, y: 6 };

//ERROR: Object literal may only specify known properties
let o2: Point = { x: 5, y: 6, z: 10 };

// OK: had I wanted to update y, but misspeled it,  
// I would get new "z" prop instead of compiler error which I would prefer to have:
let o3: Point = { ...o1, z: 10 }; 

alert(JSON.stringify(o3));

So, here is the question: how to type safely use object spread in TypeScript to update an object? Or more general question: how to update object in the functional (immutable) and a type-safe way in TypeScript 2.1?

like image 774
Oleksandr Nechai Avatar asked Dec 15 '16 07:12

Oleksandr Nechai


1 Answers

Object spread allows one to extend a base object with existing or new keys. Same with Object.assign. It's JS's dynamic nature.

If that's not what you want (It often is the case for me) then don't use Object spread or assign.

You could write a utility function locally, something like this:

function update<T, K extends keyof T>(obj: T, updateSpec: Pick<T, K>): T {
  const result = {} as T
  Object.keys(obj).forEach(key => result[key] = obj[key])
  Object.keys(updateSpec).forEach((key: K) => result[key] = updateSpec[key])
  return result
}

I think it has the semantics you want.

like image 155
AlexG Avatar answered Nov 15 '22 05:11

AlexG