Frontend Development 10 min read

Understanding JavaScript Record & Tuple Proposal: Immutable Value Types and Their Benefits

This article explains the Stage‑1 JavaScript Record & Tuple proposal, showing how the new immutable value types are created with a leading #, how they differ from objects by using value‑based comparison, and why they improve deep equality, sharing, non‑destructive updates, and usage in Maps and Sets.

360 Tech Engineering
360 Tech Engineering
360 Tech Engineering
Understanding JavaScript Record & Tuple Proposal: Immutable Value Types and Their Benefits

Dr. Axel Rauschmayer recently wrote about two Stage‑1 JavaScript features—Record and Tuple—proposed to add immutable, value‑based composite primitive types to the language.

JavaScript currently compares primitive values (e.g., strings) by value, but objects and arrays are compared by identity, meaning two distinct objects with the same content are not equal. The proposal introduces # { x: 1, y: 4 } === # { x: 1, y: 4 } // true and # [ 'a', 'b' ] === # [ 'a', 'b' ] // true to enable value comparison for composite structures.

Records are immutable objects compared by value, while Tuples are immutable arrays compared by value. They are created by prefixing an object or array literal with # . For example:

# { x: 1, y: 4 }
# [ 'a', 'b' ]

Using typeof shows that records have the primitive type 'record' and tuples have 'tuple' :

typeof # { x: 1, y: 4 } // 'record'
typeof # [ 'a', 'b' ] // 'tuple'

Records require string keys and values that are themselves primitive (including other records or tuples). Tuples require elements that are primitive values.

Objects can be shallow‑converted to records or tuples with the factory functions Record({x:1, y:4}) and Tuple.from(['a','b']) . These functions throw if any nested value is not a primitive.

Example usage of a record:

const record = # { x: 1, y: 4 };
assert.equal(record.y, 4);
const { x } = record;
assert.equal(x, 1);
assert.ok(# { ...record, x: 3, z: 9 } === # { x: 3, y: 4, z: 9 });

Example usage of a tuple:

const tuple = # [ 'a', 'b' ];
assert.equal(tuple[1], 'b');
const [ a ] = tuple;
assert.equal(a, 'a');
assert.ok(tuple.with(0, 'x') === # [ 'x', 'b' ]);
assert.ok(# [ ...tuple, 'c' ] === # [ 'a', 'b', 'c' ]);

Immutable composite values bring several advantages: deep equality becomes a built‑in operation ( === ), they can be safely shared without copying, non‑destructive updates are easy, and they work as reliable keys in Map and Set structures.

Deduplication example with Set :

new Set([ #[3,4], #[3,4], #[5,-1], #[5,-1] ]) // => Set { #[3,4], #[5,-1] }

Using composite keys in a Map :

const persons = [
  # { name: 'Eddie', address: # { street: '1313 Mockingbird Lane', city: 'Mockingbird Heights' } },
  # { name: 'Dawn',  address: # { street: '1630 Revello Drive', city: 'Sunnydale' } },
  // ...
];
const addressToNames = new Map();
for (const person of persons) {
  if (!addressToNames.has(person.address)) {
    addressToNames.set(person.address, new Set());
  }
  addressToNames.get(person.address).add(person.name);
}

Filtering objects by address using value equality:

const address = # { street: '1630 Revello Drive', city: 'Sunnydale' };
const result = persons.filter(p => p.address === address);

Checking whether cached data changed becomes trivial:

let previousData;
function displayData(data) {
  if (data === previousData) return;
  // render new data
  previousData = data;
}
displayData(#[ 'Hello', 'world' ]); // renders
displayData(#[ 'Hello', 'world' ]); // no render because === is true

Testing frameworks can use deepEqual (or the built‑in === ) directly with records and tuples:

function invert(color) {
  return # { red: 255 - color.red, green: 255 - color.green, blue: 255 - color.blue };
}
assert.ok(invert(#{ red:255, green:153, blue:51 }) === #{ red:0, green:102, blue:204 });

The new syntax has drawbacks: the # character is already used for private fields, and the literal syntax can look dense. Factory functions ( Record() , Tuple() ) and potential future tagged collection literals could improve readability.

When serialized with JSON.stringify , records become plain objects and tuples become arrays. A hypothetical JSON.parseImmutable would restore them as records and tuples.

Future work may explore making class instances immutable and value‑compared, enabling deep, non‑destructive updates of complex data structures.

JavaScriptECMAScripttupleImmutableRecordvalue comparison
360 Tech Engineering
Written by

360 Tech Engineering

Official tech channel of 360, building the most professional technology aggregation platform for the brand.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.