TC39 proposal: Record and Tuples, the real immutable data structures in JavaScript.
Tags: javascript, immutable, object, tc39
Published: 2021-04-28 10:19:41

---
title: TC39 proposal: Record and Tuples, the real immutable data structures in JavaScript.
published: true
date: 2021-04-26 11:56:40 UTC
tags: javascript,immutable,object,tc39
canonical_url: https://threkk.medium.com/tc39-proposal-record-and-tuples-the-real-immutable-data-structures-in-javascript-379e6b3089de
---

[![](https://cdn-images-1.medium.com/max/756/1*BqL1KyRs3tp5G8ski8i6AQ.png)](https://threkk.medium.com/tc39-proposal-record-and-tuples-the-real-immutable-data-structures-in-javascript-379e6b3089de?source=rss-1b85bdc283a2------2)

*This article was originally published in [Medium](https://threkk.medium.com/tc39-proposal-record-and-tuples-the-real-immutable-data-structures-in-javascript-379e6b3089de)*

Records and tuplesOne of the misleading use cases for beginners in JavaScript is to create constant arrays and objects. With the introductions of ES6, we got two new declarators: `let`, for mutable variables, and `const`, for constants. Many beginners believe that this will make their objects and array immutable, to discover later that they are not. The object or array itself is immutable, but not their content. So far, we have relied on the method `Object.freeze` to deal with this use case.

```javascript
// This is supposed to be immutable, isn't it?
const obj = { a: 1 }
obj.a = 2
console.assert(obj.a === 1, 'wtf')
// Assertion failed: wtf
```
# Introducing Record and Tuples.
Records are immutable arrays. Tuples are immutable objects. **They are compatible with Object and Array methods.** Essentially, you can drop a Tuple or a Record in any method that takes an object, or an array and it will behave as expected, unless this implies to modify the element. This applies to method of the standard library, iterators, etc.

```javascript
// Record
const record = #{ x: 1, y: 2 }
// Tuple
const tuple = #[1, 2, 3, 4]
// We can use most of the methods that work with Arrays and Objects.
console.assert(tuple.includes(1) === true, 'OK, it will not print')
// Although they will return tuples and records.
console.assert(Object.keys(record) === #['x', 'y'], 'OK, it will not print')
// Iterators work too
for (const element of tuple) {
    console.log(element)
}
// 1
// 2
// 3
// 4
// And you can nest them!
const nested = #{
  a: 1,
  b: 2,
  c: #[1, 2, 3]
}
// Nope
tuple.map(x => doSomething(x));
// TypeError: Callback to Tuple.prototype.map may only return primitives, Records or Tuples

// This is ok
Array.from(tuple).map(x => doSomething(x))
```

# However, with great power comes great responsibility.
## The power
- **Comparison by value:** Like other simple primitive types, they are compared by value, not by identity. Objects and arrays are equal if they are the same entity. Tuples and records are equal if they contain the same elements.
```javascript
const objA = {a: 1}
const objB = {a: 1}
const objC = objA
console.assert(objA === objB, 'Same content, but different entities, false')
console.assert(objA === objC, 'They are the say, it will not print')
const recordA = #{a: 1}
const recordB = #{a: 1}
const recordC = recordA
console.assert(recordA === recordB, 'OK, will not print')
console.assert(recordA === recordC, 'OK, will not print')
```
- **You can convert to objects and array and the other way around:** Using the functions `Record()` and `Tuple.from()`.

```javascript
const obj = { ...#{a: 1, b: 2}}
const record = Record({a:1, b:2})
const arr = [ ...#[1, 2, 3]]
const tuple = Tuple.from([1, 2, 3])
```

- **They are identified as distinct types:** Using the operator typeof returns unique names for each of them.
```javascript
console.assert(typeof #{a: 1} === 'record', 'this will not print')
console.assert(typeof #[1, 2] === 'tuple', 'this will not print')
```
## The responsibility
- **They can only contain primitive types:** They can only contain `String`, `Number`, `Boolean`, `Symbol`, `BigInt`, `undefined`, `null`, `Record` and `Tuple`. This is, no functions, objects, arrays, classes, etc.

- **You can use them in Maps and Sets, but not with WeakMaps and WeakSets:** Quoting from the spec

> It is possible to use a Record or Tuple as a key in a Map, and as a value in a Set. When using a Record or Tuple here, they are compared by value.
It is not possible to use a Record or Tuple as a key in a WeakMap or as a value in a WeakSet, because Records and Tuples are not Objects, and their lifetime is not observable.

- **`JSON.stringify` will work as expected, but `JSON.parse` will still return objects and arrays:** There is a proposal to add `JSON.parseImmutable` which will behave like `JSON.parse` but returning records and tuples instead of arrays and objects.

# Conclusion
This addition is welcomed as it has been a struggle to define immutable values in JavaScript, and confusing for many beginners. Prior solutions implied using external libraries like [Immutable.js](https://immutable-js.github.io/immutable-js/), workarounds in the standard library like `Object.freeze` or conventions to achieve similar results.

The proposal is currently on stage 2, so it is subject to changes. However, it already looks solid and I personally hope it makes it through and becomes a standard.

# References
- Proposal spec [[github](https://github.com/tc39/proposal-record-tuple), [web](https://tc39.es/proposal-record-tuple/)]
- [Playground](https://rickbutton.github.io/record-tuple-playground) (beware, the current specification is not fully implemented)
- [Tutorial](https://tc39.es/proposal-record-tuple/tutorial/)
- [Cookbook](https://tc39.es/proposal-record-tuple/cookbook/)