Determine the accurate data type while iterating through a for loop

I am facing an issue where I have around 40 unique actions defined, all with the same parameters except for each being provided with a different schema which is causing the problem

type ActionName = 'replaceText' | 'replaceImage';
type ActionTypes = 'element';
interface Action {
  objectId: string;
  name: ActionName;
}
interface Params<S> {
   element: {
      action: Action & S;
   }
}
const actions: Action[] = [{
  name: 'replaceImage',
  objectId: '123456'
}, {
  name: 'replaceText',
  objectId: 'replaceImage'
}];

class createAction<S, T extends ActionTypes> {
  run(params: Params<S>[T]) {
    console.log('paramas', params);
  }
}
type ReplaceImageSchema = {
  input: 'something'
}
type ReplaceTextSchema = {
  input: 'somethingElse'
}
const internalActions = {
  replaceImage: new createAction<ReplaceImageSchema, 'element'>(),
  replaceText: new createAction<ReplaceTextSchema, 'element'>()
}

for (const action of actions) {
  // the below fails because of conficting constituents
  internalActions[action.name].run({
    action
  })
  // the below works fine
  switch (action.name) {
    case 'replaceText': {
      const params = { action } as Params<ReplaceTextSchema>['element'];
      internalActions.replaceText.run(params)
    }
    break;
    case 'replaceText': {
      const params = { action } as Params<ReplaceImageSchema>['element'];
      internalActions.replaceImage.run(params)
    }
    break;
  }
}

Presently, I am using a switch statement with all available action names which is not ideal, hard to maintain, and involves repetitive code.

action.name contains the correct type with a list of available action names as string literals. Params takes a single generic of type Schema within the interface Schemas

Is there any way to solve this dynamically or is the switch statement the only solution?

It's important to mention that I have no control over which actions are available in actions in the given example. They are sent via a service.

Answer №1

In my opinion, the most efficient approach to tackle this problem is by utilizing a switch statement to thoroughly check all possible action types. However, I made an attempt to refactor the code in such a way that only one switch statement needs to be written. Below is the modified version:

type ReplaceTextAction = {
  name: 'replaceAction';
  objectId: string;
  input: string
}

type ReplaceImageAction = {
  name: 'replaceImage';
  objectId: string;
  input: string
}

type Actions = ReplaceTextAction | ReplaceImageAction

type Params = {
  element: {
    action: Actions
  }
}

class ActionHandler<T extends keyof Params> {
  async run(param: Params[T]) {
    const { name } = param.action
    switch(name) {
      case 'replaceAction':
      break;
      case 'replaceImage':
      break;
      default:
      throw new Error(`The specified action type is not handled; type = ${name}`)
    }
  }
}

const actions: Actions[] = [
  {
    name: 'replaceAction',
    input: 'something',
    objectId: '12345'
  },
  {
    name: 'replaceImage',
    input: 'somethingElse',
    objectId: '4321'
  }
]

const actionHandler = new ActionHandler()
for (const action of actions) {
  actionHandler.run({ action })
}

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

How to generate a new array in Angular by combining elements from two existing arrays for common items

I am currently working on a TypeScript function to compare two arrays and generate a third array containing the common items. For example: employees: any; offices: any; constructor() { this.employees = [ { fname: "John", lname: "James", sta ...

Casting types of objects in Angular2 using TypeScript

Trying to extract the model object from the JSON obtained through a http response call. The following JSON represents the body of the http response, { "dataType": "RWSupplier", "partyName": "Lifecare Pharmaceuticals", "partyShortName": null, "partySecon ...

Click to Rotate Angular Chevron

Is it possible to animate the rotation of a chevron icon from left-facing to right-facing using Angular? CSS: .rotate-chevron { transition: .1s linear; } HTML: <button [class.button-open]="!slideOpen" [class.button-close]="slideOpe ...

Facing issues with integrating Mixpanel with NestJS as the tracking function cannot be located

While utilizing mixpanel node (yarn add mixpanel) in conjunction with NestJS, I have encountered an issue where only the init function is recognized. Despite calling this function, I am unable to invoke the track function and receive the error message: Ty ...

Effortless implementation of list loading with images and text in the Ionic 2 framework

Can someone provide guidance on creating a lazy loading list with both images and text? I understand that each image in the list will require a separate http request to download from the server. Should caching be implemented for these image downloads? Addi ...

propagate the amalgamation of tuples as an argument

I'm working with a function that returns a union type of tuples. I need to pass this return value to another function that can accept all its forms using the spread operator .... type TupleUnion = readonly [number, number] | readonly [number, number, ...

The 'cookies' property is not found on the 'Request' type

Currently, I am attempting to access a cookie within a NestJS controller. I have been referencing the documentation found at https://docs.nestjs.com/techniques/cookies#use-with-express-default Below is my implementation: import { Controller, Get, Render, ...

The routes designed for children in the feature module are malfunctioning

Looking for help with organizing modules in a large app without cluttering the app-routing.module and app.module.ts files. Specifically focusing on managing route paths through featured modules (not using lazy loading at the moment). Encountering issues w ...

Determining the function return type by analyzing an array of functions

If you have a vanilla JavaScript function that accepts an array of callbacks (each returning an object) and combines their outputs, how can TypeScript be used to determine the return type of this function? While ReturnType is typically used for a single ...

What is causing the Typescript compiler to interpret an element in a string array as the type 'never'?

My Typescript function compiled without issue in version 3.5.3, but after updating to 3.8.3, it now throws a confusing error during compilation. import { isNumber, toInteger, padNumber } from './math'; parse(value: string): NgbDateStruct { if ...

"Uh-oh! Debug Failure: The statement is incorrect - there was a problem generating the output" encountered while attempting to Import a Custom Declarations File in an Angular

I am struggling with incorporating an old JavaScript file into my Angular service. Despite creating a declaration file named oldstuff.d.ts, I am unable to successfully include the necessary code. The import statement in my Angular service seems to be worki ...

Is there a way for me to maintain a consistent layout across all pages while also changing the content component based on the URL route in Next.js?

I'm currently working with Typescript and Next.js My goal is to implement a unified <Layout> for all pages on my website. The layout comprises components such as <Header>, <Footer>, <Sidenav>, and <Content>. Here is the ...

Distributing a library of components using Vite, Vue 3, and Typescript to npm

My current challenge involves publishing a Vue 3 component library with Vite, all written in Typescript. The issue I'm facing is that the type definitions are not being included in the package when imported into another project. Upon importing the co ...

Can you explain the significance of the 'project' within the parserOptions in the .eslintrc.js file?

Initially, I struggle with speaking English. Apologies for the inconvenience :( Currently, I am using ESLint in Visual Studio Code and delving into studying Nest.js. I find it difficult to grasp the 'project' setting within the parserOptions sec ...

Setting up APIGateway for CORS with the CDK: A Step-by-Step Guide

My API relies on AWS ApiGateway with an underlying AWS Lambda function provisioned through the CDK. The default CORS settings for the API are as follows: const api = new apiGateway.RestApi(this, "comments-api", { defaultCorsPreflightOptions: { ...

"Creating a dynamic TreeList in Ignite UI by linking pairs of names and corresponding

I recently developed a drag and drop tree list inspired by the tutorial on IgniteUI website. The main tree list functions properly, but I encountered an issue with the child nodes displaying as undefined, as illustrated in the image below: This is my Type ...

Creating Typescript libraries with bidirectional peer dependencies: A complete guide

One of my libraries is responsible for handling requests, while the other takes care of logging. Both libraries need configuration input from the client, and they are always used together. The request library makes calls to the logging library in various ...

Trouble with parsing JSON in rxjs ajax response

Currently, I am facing an issue while parsing a JSON string within an ajax callback in Angular2. After executing response.json()) and using console.log(), everything seems to be functioning correctly. This is the specific JSON data that I am attempting ...

React, redux, and redux observable are all essential tools for developing web applications. They

I am currently working on determining the type of a promise's resolve function. Here is a snippet of the code, or you can find it on GitHub: https://github.com/Electra-project/Electra-Desktop/blob/master/src/app/header/epics.ts export function getSt ...

Develop a "Read More" button using Angular and JavaScript

I am in search of all tags with the class containtText. I want to retrieve those tags which have a value consisting of more than 300 characters and then use continue for the value. However, when I implement this code: <div class=" col-md-12 col-xl-12 c ...