Mastering the art of leveraging generics in conjunction with ngrx actions

Currently, I am in the process of developing an Angular 7 application that utilizes the NGRX store. In our application, we have numerous entities, each with its own dedicated list view. I decided to explore using generics with the NGRX store to avoid writing repetitive selectors, actions, reducers, and so on for almost identical functionalities. Initially, I focused on actions and attempted to create a function that would generate a set of actions based on a generic type, but I am encountering difficulties.

    // Ensuring type safety
    enum AddTypeNames {
      ADD_REQUEST = 'AddRequestAction',
      ADD_SUCCESS = 'AddSuccessAction',
      ADD_FAILURE = 'AddFailureAction',
    }
    // Constructing an object literal with a string key and Action as the value
    function createAddActions<T>(featureName: string): { [key in AddTypeNames]: Action } {
      class AddRequestAction implements Action {
        readonly type = `[${featureName}] Add request`;
        constructor(payload: { entity: T }) { }
      }
      class AddSuccessAction implements Action {
        readonly type =  `[${featureName}] Add success`;
        constructor(payload: { entity: T }) { }
      }
      class AddFailureAction implements Action {
        readonly type =  `[${featureName}] Add error`;
        constructor(payload: { error: HttpErrorResponse }) { }
      }
      return {
        AddRequestAction,
        AddSuccessAction,
        AddFailureAction,
      };
    }

While working on this implementation, I encountered an error message in the editor:

(property) AddRequestAction: Action
Property 'type' is missing in type 'typeof AddRequestAction' but required in type 'Action'.ts(2741)

I am unsure about the meaning of this particular error, especially since it appears that the type is defined within the class. Is my approach correct? How can I effectively create actions with generic types? Moreover, is leveraging generics extensively considered a best practice in such scenarios?

Answer №1

The reason for the compilation error is that you specified that createAddActions will return a dictionary of Action objects as

{ [key in AddTypeNames]: Action }
. However, this syntax indicates an object of instances of the Action class, not the classes themselves.

Therefore, you informed TypeScript that your return object values contain the attribute 'type', which your classes do not have as a static attribute type.

If you intend to declare that the function's result is an object with classes (not instances of them), use this syntax instead: { new (...args): Action }.

So:

function createAddActions<T>(featureName: string): { [key in AddTypeNames]: { new (...args): Action } } {

will resolve the compilation error.

Playground

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

Strategies for ensuring that code does not execute in Angular until the API response has been received

Currently, I am facing an issue where I need to wait for data from an API in order to set the value of a variable and use it in an if condition. The problem lies in my uncertainty about how to properly handle this asynchronous task using async and await. ...

Having trouble configuring Jest for TypeScript integration

I am currently implementing unit testing for a typescript project following the guidelines in this example: https://dev.to/muhajirdev/unit-testing-with-typescript-and-jest-2gln In my project, I have a file named main.ts that exports an isInternalLink func ...

Adding a fresh element to an array in Angular 4 using an observable

I am currently working on a page that showcases a list of locations, with the ability to click on each location and display the corresponding assets. Here is how I have structured the template: <li *ngFor="let location of locations" (click)="se ...

Error encountered in Vue 3 typescript: Uncaught TypeError - this.$on function is not defined in this context

Just set up a fresh installation of Vue 3 using vue-cli and typescript. Everything seems to be running smoothly, but as soon as I incorporate the https://vue-select.org/ package, I encounter this error in the browser console: Uncaught (in promise) TypeErro ...

Is there a possible solution to overcome the type error when utilizing dynamic environment variables in conjunction with TypeORM and TypeScripts?

I'm currently working on a backend project using the TsED framework, which leverages TypeScript and ExpressJS. To work with TypeORM, I have also integrated the dot-env package in order to utilize custom environment variables sourced from a .env file ...

Bringing in AuthError with TypeScript from Firebase

Is it possible to verify if an error is of type "AuthError" in TypeScript when using Firebase? I have a Https Callable function with a try/catch block that looks like this: try { await admin.auth().getUser(data.uid); // will throw error if user doesn& ...

Tips for setting ngModel and name attributes in an angular test for a custom component

Just getting started with angular. I recently developed a custom component that implements the ControlValueAccessor to allow developers to easily access its value. Here's an example of how it can be used: <app-date [label]="'Date 2&apos ...

Troubleshooting TypeScript errors related to ReactNode post-upgrade to Create React App v5

Since upgrading to Create React App version 5, I've been encountering errors like the one below: TS2786: 'OutsideClickHandler' cannot be used as a JSX component. Its instance type 'OutsideClickHandler' is not a valid JSX element. ...

Is it possible to execute "green arrow" unit tests directly with Mocha in IntelliJ IDEA, even when Karma and Mocha are both installed?

My unit tests are set up using Karma and Mocha. The reason I use Karma is because some of the functionality being tested requires a web browser, even if it's just a fake headless one. However, most of my code can be run in either a browser or Node.js. ...

Creating a customized HTTP class for Bootstrap in Angular 2 RC 5

During my experience with Angular 2 RC 4, I encountered a situation where I needed to create a class called HttpLoading that extended the original Http class of Angular2. I managed to integrate this successfully into my project using the following bootstr ...

MongoDB NextJS connection issue "tried to retrieve a connection from a closed connection pool"

I am attempting to establish a connection to my MongoDB database in order to retrieve some information. When setting up the connection without fetching any data, everything works fine. However, when trying to fetch data, the console throws this error: at ...

Cannot display data in template

After successfully retrieving JSON data, I am facing trouble displaying the value in my template. It seems that something went wrong with the way I am trying to output it compared to others. My function looks like this, getUserInfo() { var service ...

Updating the style of different input elements using Angular's dynamic CSS properties

I am seeking guidance on the proper method for achieving a specific functionality. I have a set of buttons, and I would like the opacity of a button to increase when it is pressed. Here is the approach I have taken so far, but I have doubts about its eff ...

Angular 2 Google Chart: Defining column type using TypeScript

I am currently attempting to implement the Timeline chart functionality from the angular2-google-chart module for Google Charts. Unlike the other examples provided, this specific chart type requires a column type definition — a requirement not present in ...

Creating personalized breakpoints in Material UI using TypeScript

When using the createMuiTheme() function, you have the ability to update breakpoint values like this. const theme = createMuiTheme({ breakpoints: { values: { xs: 0, sm: 600, md: 960, lg: 1280, xl: 1920, }, }, }) ...

In fact, retrieve the file from an S3 bucket and save it to your local

I've been attempting to retrieve an s3 file from my bucket using this function: async Export() { const myKey = '...key...' const mySecret = '...secret...' AWS.config.update( { accessKeyId: myKey, secretAcces ...

Guide to extracting the JSON array from a JSON object with Angular

In my angular application, I have made a call to the API and retrieved a JSON object in the console. However, within this JSON object, there are both strings and arrays. My task now is to extract and parse the array from the object in the console. The JSO ...

Is it possible to pass a Styled Components Theme as Props to a Material UI element?

After spending 9 hours scouring the internet for a solution, I am at my wit's end as nothing seems to work. Currently, I am developing a React component using TypeScript. The issue lies with a simple use of the Material UI Accordion: const Accordion ...

What is the best way to delete previously entered characters in the "confirm password" field after editing the password

Is there a way to automatically remove characters in the confirm password field if characters are removed from the password field? Currently, when characters are entered into the password field, characters can also be entered into the confirm password fiel ...

Is there a technique to block small increments in a Time Input field?

Currently in the process of developing a tool to automate task scheduling within an Angular app. I am looking for a way to restrict the user's input when selecting the hour for task execution without having to install a complex input management packag ...