Home > Mobile >  How to make a frozen set in Typescript?
How to make a frozen set in Typescript?

Time:04-03

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 aPressed = 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')

CodePudding user response:

You can make a type that leaves out the add function from the Set type:

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

listenedKeys.add('r') // error

You may want to omit 'clear' and 'delete' too.

Omit<Set<string>, 'add' | 'clear' | 'delete'>

If you're doing this a lot, you may want to make a helper type for it:

type ReadOnlySet<T> = Omit<Set<T>, 'add' | 'clear' | 'delete'>

Playground link

CodePudding user response:

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

CodePudding user response:

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

CodePudding user response:

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

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

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

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

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

  • Related