Creating a TypeScript frozen set: A step-by-step guide

Imagine having a group of values that you want to protect from being edited, as shown below:

// These values should not be editable.
const listenedKeys = new Set(['w', 'a', 's', 'd'])

// This value can be accessed without issues.
const hasA = listenedKeys.has('a')

// Attempting to modify this should cause an error.
listenedKeys.add('r')

Is it possible to make this set immutable in TypeScript? If so, how?

I've attempted using the Readonly utility type, but it did not prevent me from making changes to the set:

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

// No errors occur during this operation
listenedKeys.add('r')

Answer №1

There is native support for this type in TypeScript, known as ReadonlySet. It will prevent any modifications to the set once it has been created.

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

Playground Link

If you prefer implicit typing, a small helper function can be created specifically for switching types:

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

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

Playground Link

The definition of this type can be found in the es2015.collection.d.ts file, along with similar types like ReadonlyMap.

Answer №2

If you want to create your own custom interface, you can do so by extending an existing one like this:

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

Check out the playground here

Answer №3

To prevent the add property from being used on the listenedKeys variable, you can create a new type called MyNewSet:

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

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

const aPressed = listenedKeys.has('a')

listenedKeys.add('r') // error

Check out this playground link to see it in action: Playground Link

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What exactly does the use of type assertion as any in Typescript entail?

I'm attempting to dissect a portion of code and figure out its functionality. While I've encountered type assertion before, this particular example is proving to be quite baffling for me. (this.whatever as any).something([]); Here's the la ...

Utilizing MongoDB query for geoLocation with maxDistance parameter

Customer location: customerCoordinates: [83,24] stores: { id:1, location: {coordinates:[85,44]...} maxRadiusDelivery: 2000 //meters }, { id:2, location: {coordinates:[82,34]...} maxRadiusDelivery: 100 //meters } Query: db.wh.find({ 'locati ...

Does a typescript definition file exist for Apple MapKit JS?

Before embarking on creating one, I'm curious if anyone has come across a typescript definition file (.d.ts) for Apple MapKit JS? ...

Exploring ways to destructure the useContext hook with a null default value in your Typescript code

Initially, I set up a context with a null value and now I am trying to access it in another component. However, when I destructure it to retrieve the variables from the context, I encounter a TypeScript error: Property 'users' does not exist on ...

Encountered an issue during the migration process from AngularJS to Angular: This particular constructor is not compatible with Angular's Dependency

For days, I've been struggling to figure out why my browser console is showing this error. Here's the full stack trace: Unhandled Promise rejection: NG0202: This constructor is not compatible with Angular Dependency Injection because its dependen ...

The SonarTsPlugin report is coming back clean with no issues found in the Typescript files

In my current project, I am attempting to analyze an Angular application using SonarQube. This particular project consists of a mix of JavaScript and TypeScript files. During the Sonar analysis process, I have noticed that while issues are being generated ...

How can users create on-click buttons to activate zoom in and zoom out features in a Plotly chart?

I am currently working on an Angular application where I need to implement zoom in and zoom out functionality for a Plotly chart. While the default hoverable mode bar provides this feature, it is not suitable for our specific use case. We require user-cr ...

Issues arise when upgrading from Angular 8 to 9, which can be attributed to IVY

After successfully upgrading my Angular 8 application to Angular 9, I encountered an error upon running the application. { "extends": "./tsconfig.json", "compilerOptions": { "outDir": ". ...

The error message "this.startLoginAnimatioon is not defined as a function" popped up

I've been developing a login system using TypeScript but I keep encountering an error that I can't figure out. Here's the issue in detail: https://i.sstatic.net/PN4N8.png The problem arises when the this.startLoginAnimation() function ...

Jest is having difficulty locating a module while working with Next.js, resulting in

I am encountering some difficulties trying to make jest work in my nextjs application. Whenever I use the script "jest", the execution fails and I get the following result: FAIL __tests__/index.test.tsx ● Test suite failed to run ...

What is the relationship between Typescript references, builds, and Docker?

I am facing a dilemma with my projectA which utilizes a common package that is also needed by my other Nodejs services. I am unsure of the best approach to package this in a Docker file. Ideally, running tsc build would compile both the project and the dep ...

What is causing the failure of the state to be inherited by the child component in this scenario (TypeScript/React/SPFX)?

For this scenario, I have a Parent class component called Dibf and a Child class component named Header. While I can successfully pass props from the Parent to the child, I am encountering difficulties when trying to pass state down by implementing the fo ...

Is there a more concise method for accepting a collection of interfaces in TypeScript?

Issue I am facing a simplified version of a problem with my model: Here is how my model currently looks: interface Instrument { name: string; // ...more properties shared by all instruments... } interface Guitar extends Instrument { type: &q ...

Is ConnectionServiceModule not compatible with Angular version 17.2.0?

I have encountered an issue in my Angular project that involves the compatibility of the ng-connection-service library with Angular Ivy. When I attempt to bring in the ConnectionServiceModule from the ng-connection-service into my Angular module, I am rece ...

How can I display images stored locally within a JSON file in a React Native application?

Hey everyone, I'm currently facing an issue with linking a local image from my images folder within my JSON data. Despite trying various methods, it doesn't seem to be working as expected. [ { "id": 1, "author": "Virginia Woolf", " ...

Problem with Anular5 - "this" not functioning correctly inside of ready()

I am encountering an issue in graph.component.ts this.cContainer = cytoscape ( { ready: function(e) { this._dataService.setResultData(); } }); However, I am getting the following error message: ERROR TypeError: Cannot read property &ap ...

The data type 'Event' cannot be assigned to the data type 'string' in this context

Recently diving into Angular, I came across a stumbling block while working through the hero tutorial. The error message that popped up was: Type 'Event' is not assignable to type 'string' You can see the error replicated here. ...

Best practices for extending the Array<T> in typescript

In a discussion on extending the Static String Class in Typescript, I came across an example showing how we can extend existing base classes in typescript by adding new methods. interface StringConstructor { isNullOrEmpty(str:string):boolean; } String. ...

typescript exploring the versatility of dynamic types and generics

Understanding TypeScript dynamic and generic types can be challenging for me. The goal is to create a function that generates an object with a specific type, where some properties of the object must match the parameters provided to the function. Essentia ...

Ways to access nested keys in a TypeScript object as well as an array containing objects

As I develop a form generator, my goal is to achieve type safety for a nested object and an array of objects. Specifically, I want the 'name' property to correspond to the key of the respective object it belongs to. For instance, in the scenario ...