1 of 16

Spreading nullish values

To throw or not to throw?

2 of 16

// Array spreadconst mergedArray = [...array1, ...array2];// → throws if e.g. `array2` is `null` or `undefined`��// Object spreadconst mergedObject = { ...object1, ...object2 };// → ignores e.g. `object2` if it’s `null` or `undefined`

3 of 16

  • Leave things as they are and live with the inconsistency

Option 1

4 of 16

  • Tighten up object spread to match array spread
  • Throw when spreading null or undefined
  • Pro:
    • Is explicit rather than implicit
    • Makes bugs (e.g. accidental undefined) more detectable
  • Con:
    • Inconsistent with Object.assign and similar userland utilities

Option 2

5 of 16

  • Relax array spread to match object spread
  • null and undefined spread to nothing
  • Pro:
    • Seems like the smallest possible non-breaking change
    • Consistent with object spread
  • Con:
    • Potentially hides bugs
    • Still not consistent with iteration: null & undefined still not iterable

Option 3

6 of 16

  • Make null and undefined iterable (producing no values)
  • Pro:
    • Would fix this behavior in general, not just for array spread specifically
  • Con:
    • Potentially hides bugs (e.g. accidental undefined)

Option 4

7 of 16

  1. leave things as-is
  2. tighten up object spread, disallow spreading nullish values
  3. relax array spread; allow spreading nullish values
  4. make null and undefined iterable

Options: recap

8 of 16

9 of 16

Object spread rationale

10 of 16

null | undefined | Point3D

Not very common type:

{} | Point3D

11 of 16

?Point3D

Not very common type:

{} | Point3D

12 of 16

{ ...obj || {} }

We don’t recommend obj || {} as a pattern elsewhere.

13 of 16

obj ? { foo: obj.foo, bar: obj.bar, baz: value } : { baz: value }

{ ...obj, baz: someValue }

{ ...(obj || {}), baz: someValue }

14 of 16

arr ? [arr[0], arr[1], arr[2], value] : []

[ ...arr, value ]

[ ...(arr || []), value ]

15 of 16

{ ...obj, foo: {...obj?.foo, bar: 1 }}

16 of 16

{ ...obj || {}, foo: {...obj?.foo || {}, bar: 1 }}