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'>
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')
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')
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']))