Explaining how to use the describe function in TypeScript for mapping class constructors

I am working on a function that will return a JavaScript Object with the class instances as values and the class names as keys.

For example:

const init = (constructorMap) => {
    return Object.keys(constructorMap).reduce((ret, constructorName) => {
         ret[constructorName] = new (constructorMap[constructorName])();
         return ret;
     }, {});
};

class C1 {};
class C2 {};
const instances = init({C1: C1, C2: C2});

How can I write this in TypeScript?

Answer №1

To achieve this functionality, you can utilize the InstanceType feature along with a custom mapped type. While some type assertions are required in the implementation process, the overall call site will remain completely type safe.

type InstanceTypes<T extends Record<keyof T, new () => any>> = {
    [P in keyof T]: InstanceType<T[P]>
}
const initialize = <T extends Record<keyof T, new () => any>>(constructorsMap: T): InstanceTypes<T>  => {
    return (Object.keys(constructorsMap) as Array<keyof T>).reduce((result, constructorName) => {
        result[constructorName] = new (constructorsMap[constructorName])();
        return result;
    }, {} as InstanceTypes<T>);
}

class MyClass1 { prop1!: number};
class MyClass2 { prop2!: string};
const instancesCollection = initialize({MyClass1: MyClass1, MyClass2: MyClass2});
instancesCollection.MyClass1.prop1;
instancesCollection.MyClass2.prop2

Try out the code snippet here.

Answer №2

To create a custom InstanceMap type, you can utilize the built-in InstanceType:

type InstanceMap<C extends Record<string, new () => any>> = {
  [k in keyof C]: InstanceType<C[k]>
};

function initialize<C extends Record<string, new () => any>>(classMap: C): InstanceMap<C> {
  // your code implementation goes here
  return {} as any
}

class MyClass1 { method1() {} }
class MyClass2 { method2() {} }
const myClassesMap = { MyClass1, MyClass2 };

const instances = initialize(myClassesMap);
instances.MyClass1.method1();
instances.MyClass2.method2();

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

Jest's it.each method is throwing an error: "This expression is not callable. Type 'String' has no call signatures."

I've been attempting to utilize the describe.eachtable feature with TypeScript, but I keep running into an error message stating: "error TS2349: This expression is not callable. Type 'String' has no call signatures." Below is my code snippe ...

Expanding Mongoose Schema with Typescript: A Comprehensive Guide

Currently, I am in the process of creating 3 schemas (article, comment, user) and models that share some common fields. For your information, my current setup involves using mongoose and typescript. Mongoose v6.1.4 Node.js v16.13.1 TypeScript v4.4.3 Eac ...

esLint throws an error advising that a for-in loop should be enclosed within an if statement in order to exclude unnecessary properties from the prototype

While working on my Angular project, I encountered an error with esLint related to the code snippet below: private calculateFieldValue(value: any): any { let isEmptyObject = false; if (value && Array.isArray(value) & ...

Despite the presence of a producer and topic, sending Kafka messages is proving to be a challenge

Currently, I am using TypeScript and the KafkaJS library on my local machine with a single Kafka broker. After successfully connecting a producer, confirming the creation of my topic, and creating messages like so: const changeMessage = { key: id, ...

script not found: typings-install

When running the command npm run typings-install, I encountered the following error: npm ERR! Windows_NT 6.1.7601 npm ERR! argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Program Files\\nodejs\\n ...

Tips for customizing the `src/app/layout.tsx` file in Next.js 13

I am looking to customize the layout for my /admin route and its child routes (including /admin/*). How can I modify the main layout only for the /admin/* routes? For example, I want the / and /profile routes to use the layout defined in src/app/layout.ts ...

Requires the refreshing of an Angular component without altering any @Input properties

Currently delving into the world of Angular (along with Typescript). I've put together a small application consisting of two components. This app is designed to help track work hours (yes, I am aware there are commercial products available for this pu ...

Upon executing the `npm start` command, the application experiences a crash

When I tried following the steps of the Angular quickstart guide, I encountered some errors after running "npm start". Here are the errors displayed: node_modules/@angular/common/src/directives/ng_class.d.ts(46,34): error TS2304: Cannot find name 'Se ...

What are the best ways to enhance change detection efficiency in Angular?

One issue I am facing involves two components and a service. It appears that when moving from the view of a routed component to elements in different components like a matMenu and an input field, the routed component seems to refresh itself. This becomes p ...

Looking to retrieve CloudWatch logs from multiple AWS accounts using Lambda and the AWS SDK

Seeking guidance on querying CloudWatch logs across accounts using lambda and AWS SDK Developing a lambda function in typescript Deploying lambda with CloudFormation, granting necessary roles for reading from two different AWS accounts Initial exe ...

What is the process for removing globally declared types in TypeScript definitions?

There are numerous libraries that cater to various platforms such as the web, Node servers, and mobile apps like React Native. This means they can be integrated using <script /> tags, require() calls, or the modern import keyword, particularly with t ...

Declaring scoped runtime interfaces with Typescript

I need to create a global interface that can be accessed at runtime under a specific name. /** Here is my code that will be injected */ // import Vue from "vue"; <- having two vue instances may cause issues // ts-ignore <- Vue is only ava ...

Unable to find any routes that match child routes using the new Angular 2 RC1 router

ApplicationComponent import { Component } from '@angular/core'; import {Router, ROUTER_DIRECTIVES, Routes, ROUTER_PROVIDERS} from '@angular/router'; import {SchoolyearsComponent} from "./schoolyear/schoolyears.component"; @Component({ ...

Incorporating additional properties into a TypeScript interface for a stateless, functional component within a React Native application

When following the React Native documentation for consistent styling, a recommendation is made to create a <CustomText /> text component that encapsulates the native <Text /> component. Although this task seems simple enough, I'm facing d ...

What is the best way to create an array of strings that can include multiple elements from a set of strings?

Exploring different roles for authorization: ['admin', 'manager', 'user'] Is there a way to create a specific type, named Roles, which is essentially a string array ( string[] ) that is limited to only containing values from ...

Using forEach in React to simultaneously set multiple properties and return destructured output within the setState function

The following is the initial code snippet: setRows((rows) => rows.map((row) => selected && row.node === selected.id ? { ...row, row.a: "", row.b: "", row.c: "" } ...

Why is the Last Page display on pagination showing as 3 instead of 2 per items?

When working on Angular 13, I encountered an issue with applying pagination numbers like 1, 2, 3, etc. The problem I faced was that the last page Number should be 2, but it is displaying as 3. Why is this happening? To investigate the issue, I tested my ...

An asynchronous function operates incessantly

I have implemented the following code in React using hooks to fetch data from two different sources. const [ permissionTree, setPermissionTree ] = useState([]); const [ availablePermissionsInRole, setAvailablePermissionsInRole ] = useState<Permission[] ...

What are the steps to incorporate a type-safe builder using phantom types in TypeScript?

In order to ensure that the .build() method can only be called once all mandatory parameters have been filled, it is important to implement validation within the constructor. ...

What is the method for defining a mandatory incoming property in an Angular2 component?

In my current project, I am developing a shared grid component using Angular2 that requires an id property. export class GridComponent { @Input() public id: string; } I'm looking for a way to make the id property mandatory. Can you help me with ...