How to make a frozen set in TypeScript?

Viewed 109

Let's say I have a set of values that I don't want to be editable, like this:

// I don't want this to be editable.
const listenedKeys = new Set(['w', 'a', 's', 'd'])

// This should be fine.
const hasA = listenedKeys.has('a')

// I want this to give an error.
listenedKeys.add('r')

Can I "freeze" this set in TypeScript? How?

I've tried using the Readonly utility type, but that doesn't prevent me from modifying the set:

const listenedKeys: Readonly<Set<string>> = new Set(['w', 'a', 's', 'd'])

// No error here
listenedKeys.add('r')
3 Answers

TypeScript already supports this type natively. It is called ReadonlySet and will do exactly what you want - you will not be allowed to modify the set once created

const listenedKeys: ReadonlySet<string> = readOnlySet(new Set(['w', 'a', 's', 'd']))

Playground Link

If you want to use implicit typing, you can create a small helper function that will serve only to switch the types:

const readonlySet = <T>(set: Set<T>): ReadonlySet<T> => set;

const listenedKeys = readonlySet(new Set(['w', 'a', 's', 'd']))

Playground Link

The type is defined in the es2015.collection.d.ts file alongside analogous types ReadonlyMap.

You can make your own interface by inherit like:

interface FrozenSet<T> extends Set<T> {
  add: never,
}

class FrozenSet<T> extends Set<T> implements FrozenSet<T> {}

const listenedKeys = new FrozenSet(['w', 'a', 's', 'd'])

// @ts-expect-error
listenedKeys.add('r')

See playground

You can simply create a new type which will omit the add property and prevent it from being used on the listenedKeys variable:

type MyNewSet = Omit<Set<string>, 'add'>;

const listenedKeys: MyNewSet = new Set(['w', 'a', 's', 'd'])

const aPressed = listenedKeys.has('a')

listenedKeys.add('r') // error

Here is a link to the playground: Link

Related