Guide on creating a detailed list of categories mapped to specific classes that all adhere to a common generic standard

Most TypeScript factory patterns I've encountered rely on a named mapping between a name and the Class type.

A basic implementation example:

const myMap = {
 classOne: ExampleClass,
 classTwo: AnotherClass
}

(k: string) => { return new myMap[k] }

I wanted to elevate this mapping concept - as my classes follow the structure of ExampleClass implementing iGenericInterface<T>

However, I'm struggling to specify that Record Value types should be restricted to those implementing the iGenericInterface<T>. The problematic area in the following example is marked with ***

export interface iGenericInterface<K> {
  process(input: K): void
}

class ExampleClass implements iGenericInterface<string> {
  process(input: string): void {
    console.log(input);
  }
}

class AnotherClass implements iGenericInterface<number> {
  process(input: number): void {
    console.log(input);
  }
}

class UnsupportedClass {
  otherMethod(input: boolean): void {
    console.log(input);
  }
}

enum instantiableClassesEnum { class1, class2, class3 };
type enumValues = keyof typeof instantiableClassesEnum;
type logicStore<T> = Record<enumValues, ***iGenericInterface<T>***>

const classMap: logicStore<any> = {
    class1: ExampleClass,
    class2: AnotherClass,
    class3: UnsupportedClass,
};

I would anticipate an error for the UnsupportedClass, but desire acceptance by the compiler for the others.

If I change ExampleClass to an instance like class1: new ExampleClass, the compiler is content. However, I then face uncertainty regarding how to utilize the mapping in the factory method - return new myMap[k]

EDIT - (@Adriaan This is NOT an answer, just a clarification of the end goal) Ability to generate classes based on Enumeration input - utilizing the mapped structure above.

class LogicFactory {
  static createLogic<T>(logicClass: enumValues): 
  iGenericInterface<T> {
  return new classMap[logicClass]();
}

}

Answer №1

To utilize the Constructor<T> type, follow this code snippet:

type _builtin = InstanceType<any> // T extends abstract new (...args: any) => infer R ? R : any
type Constructor<T> = new (...args: any) => T

enum instantiableClassesEnum { class1, class2, class3 };
type enumValues = keyof typeof instantiableClassesEnum;
type logicStore<T> = Record<enumValues, Constructor<iGenericInterface<T>>>

const classMap: logicStore<any> = {
    class1: ExampleClass,
    class2: AnotherClass,
    class3: UnsupportedClass, // Property 'process' is missing in type 'UnsupportedClass'
};

Answer №2

After reviewing @Dimava's solution on how to establish the Enum - Constructor correlation, the desired outcome has been successfully attained:

Below is an elaborate explanation of the solution provided by @jcalz

type Constructor<T> = new (...args: any) => T
enum instantiableClassesEnum { class1, class2, class3 };
type enumValues = keyof typeof instantiableClassesEnum;
type logicStore<T> = Record<enumValues, 
Constructor<iGenericInterface<T>>>

const classMap: logicStore<any> = {
    class1: ExampleClass,
    class2: AnotherClass,
    class3: UnsupportedClass,
};


class LogicFactory {
  static createLogic<T>(logicClass: enumValues): iGenericInterface<T> {
    return new classMap[logicClass]();
  }
}

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

Adding to an existing array in SQLite by updating a column using Sequelize

My code includes a model definition for saving product data using Sequelize: This is how the Product model looks: import {Optional, Model, Sequelize, DataTypes } from 'sequelize'; /*This is the Product model used to save the data about products* ...

Utilize functional JS code within a TypeScript environment

Attempting to integrate this code into a TypeScript project, it is a modified version of the react-custom-scrollbars. I am struggling with TypeScript in regards to declaring types for style and props. In this particular case, I prefer to bypass type check ...

`Measuring Code Coverage in Jasmine Unit Tests`

Looking for assistance with unit testing my simple logger .ts file. Can someone help me fix the unit test? logging.service.ts import 'reflect-metadata'; // Required for tsyringe import { singleton } from 'tsyringe'; import { Category } ...

Guide to highlighting input field text using Angular

I've set up an angular page that includes an input field within its template. My goal is to highlight the text in the input field when a specific function is triggered. When I refer to "highlighting the text," I mean (check out the image below) https ...

Encountering a Next.js event type issue within an arrow function

After creating my handleChange() function to handle events from my input, I encountered an error that I'm unsure how to resolve. Shown below is a screenshot of the issue: I am currently working with Next.js. In React, this type of error has not been ...

Discover a more efficient method for expanding multiple interfaces

Hey there, I'm having some trouble with TypeScript and generics. Is there a better way to structure the following code for optimal cleanliness and efficiency? export interface Fruit { colour: string; age: number; edible: boolean; } export inte ...

Using RxJS switchMap in combination with toArray allows for seamless transformation

I'm encountering an issue with rxjs. I have a function that is supposed to: Take a list of group IDs, such as: of(['1', '2']) Fetch the list of chats for each ID Return a merged list of chats However, when it reaches the toArray ...

Ways to assign values to an array within an object

I'm attempting to transfer the contents of one array into an array within an object, but I keep encountering this error: Type 'any[]' is not assignable to type '[]'. Target allows only 0 element(s) but source may have more. Here ...

What steps should I take to verify the validity of an Angular form?

I am struggling with validating an inscription form in HTML. Despite trying to implement validations, the inputs are still being saved in the database even when they are empty. Here are the validations I want to include: All inputs are required Email addr ...

"Troubleshooting the issue of Angular's select binding causing a disruption

The Angular version being used is 1.4.7. Within the model in question, there are two objects: 'systems', which is an array, and 'selectedSystem'. The desired outcome is for 'selectedSystem' to reference one of the objects wit ...

What is the most effective method for dividing a string in TypeScript?

Here is the scenario: receiving a string input that looks like Input text: string = "today lunch 200 #hotelname" Output subject: "today lunch" price: 200 tag: #hotelname My initial solution looks like this: text: string = "today lunch 200 #hotelname" ...

Unable to make a reference to this in TypeScript

In my Angular2 application, I have a file upload feature that sends files as byte arrays to a web service. To create the byte array, I am using a FileReader with an onload event. However, I am encountering an issue where I cannot reference my uploadService ...

Error in Typescript: The property 'a' is not defined in the type 'A'

Here is an example of the different types I am working with: type Place = { address: string } type Location = { latLng: string } type User = { name: string } & (Place | Location) When attempting to parse the data using this structure, I enco ...

The latest release of Angular2, rc1, eliminates all parameters that are not in

In the previous beta version, I was able to analyze using split Location.path(), but now it seems to have been removed. How can I prevent this removal? Interestingly, everything works well with matrix parameters (;id=123;token=asd). This was tested on a ...

Having trouble accessing previously submitted form values in Angular

When I try to update the form, I notice that my meetupform.controls.day array is not retaining the previously selected values app.component.html <div *ngIf="meetupForm.controls.recurring.value==='weekly'"> <mat-checkbox (change)="o ...

What is the best way to make cypress.io swipe an ionic ion-item-sliding component to the left?

I am currently working on a small ionic 4 (vue) app that includes an ion-list with ion-item-sliding. Here is a snippet of the code: HTML <ion-item-sliding v-for="day in month.days" v-bind:key="day.day"> <ion-item :id ...

What steps can I take to have TypeScript limit the type of an array based on filter inference?

Here's a handy function that always returns an array of strings: (arr: (string | undefined)[]): string[] => arr.filter(item => item !== undefined); Check it out here However, TypeScript may not compile this code as expected due to its inferenc ...

Next.js: Importing from a new endpoint triggers the code execution once more

Here is a simplified example I created for this specific question. Imagine I want to maintain a server-side state. components/dummy.ts console.log('initialize array') let number: number = 0 const incrementValue: () => number = () => numbe ...

What is the correct way to specify the data type for the useState hook when I intend to store an array of objects?

My dilemma involves storing an array of objects using the useState hook, but I am struggling with the syntax required to describe the expected type. The type that I want to store is Array<Updates>. Below is the code I have: const [messages, setMessa ...

Record the variable as star symbols in the VSTS Extension

I am working on a VSTS extension using Typescript and utilizing the vsts-task-lib Currently, I am encountering an issue with the execSync function, which displays the command being executed. However, I need to hide a token obtained from a service by displ ...