Definition of type instantiation in TypeScript

When utilizing the mynew function with a specified array of classes, I am encountering an error related to defining unknown. How can I modify this definition in order to eliminate the error?

export interface Type<T> extends Function {
  new (...args: any[]): T;
}

function mynew(klass: Type<unknown>[]): unknown[] {
  return klass.map((e) => new e());
}

class ClassA { x = 1 }
class ClassB { y = 1 }

const [a, b] = mynew([ClassA, ClassB]);


// The attribute "x" does not exist on the type "unknown"
a.x

// The attribute "y" does not exist on the type "unknown"
b.y;

Answer №1

Let's create a solution that eliminates the need to manually input generics for each class.

Initially, you can simplify this code:

export interface Type<T> extends Function {
  new (...args: any[]): T;
}

to:

type Constructor<T> = new (...args: any[]) => T

To minimize repetitive code, utilize variadic tuple types.

In order to deduce the constructor of each class, apply them in this manner:

function mynew<T extends Constructor<any>, Classes extends T[]>(...klasses: [...Classes]) {
    return klasses.map((e) => new e());
}

const result = mynew(ClassA, ClassB)

If you hover over mynew(ClassA, ClassB), you'll notice that the second generic argument Classes is inferred as [typeof ClassA, typeof ClassB].

Now, let's iterate through each element in the tuple and acquire [InstanceType][2]

This is how it can be achieved:

type MapPredicate<T> = T extends Constructor<any> ? InstanceType<T> : never

type Mapped<
    Arr extends Array<unknown>,
    Result extends Array<unknown> = []
    > = Arr extends []
    ? []
    : Arr extends [infer H]
    ? [...Result, MapPredicate<H>]
    : Arr extends [infer Head, ...infer Tail]
    ? Mapped<[...Tail], [...Result, MapPredicate<Head>]>
    : Readonly<Result>;

// [ClassA, ClassB] 
type Result = Mapped<[typeof ClassA, typeof ClassB]>    

Remember, there exists a significant difference between the type typeof ClassA and ClassA. The former refers to the constructor, while the latter indicates the class instance.

Let’s combine everything together:

type Constructor<T> = new (...args: any[]) => T

class ClassA { x = 1 }
class ClassB { y = 1 }
class ClassC { z = 1 }

type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
    k: infer I
) => void
    ? I
    : never;

type MapPredicate<T> = T extends Constructor<any> ? InstanceType<T> : never

type Mapped<
    Arr extends Array<unknown>,
    Result extends Array<unknown> = []
    > = Arr extends []
    ? []
    : Arr extends [infer H]
    ? [...Result, MapPredicate<H>]
    : Arr extends [infer Head, ...infer Tail]
    ? Mapped<[...Tail], [...Result, MapPredicate<Head>]>
    : Readonly<Result>;

// [ClassA, ClassB] 
type Result = Mapped<[typeof ClassA, typeof ClassB]>    

function mynew<T extends Constructor<any>, Classes extends T[]>(...klasses: [...Classes]): Mapped<Classes> & unknown[]
function mynew<T extends Constructor<any>, Classes extends T[]>(...klasses: [...Classes]) {
    return klasses.map((e) => new e());
}

const result = mynew(ClassA, ClassB, ClassC)
const [a, b, c] = result;
a.x // ok
b.y // ok
c.z // ok

Playground

For more information on iterating through tuple types, refer to my blog

Answer №2

Here is my proposed solution, but I am open to suggestions for improvement

function createInstances<A, B>(classes: [Type<A>, Type<B>]): [A, B];
function createInstances<A>(classes: [Type<A>]): [A];
function createInstances(classes: Type<any>[]): any {
  return classes.map((element) => new element());
}

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

Leveraging Generic Types in React with TypeScript for Dynamically Assigning HTML Props based on Element Tags

I am frequently in need of a component that is essentially just a styled HTML tag. A good example is when I want to create beautifully styled div elements: // Definitions const styledDiv = (className: string) => { const StyledDiv = React.FC<HTMLA ...

Is there a way to toggle the visibility of the angular material toolbar at regular intervals?

I'm currently experimenting with the CSS animation feature to display and conceal the angular material toolbar in this demonstration. Inside the application component, the hide attribute is toggled at intervals as shown below: hide:boolean = false ...

How to access type properties in typescript without using the "this" keyword

Below is a snippet of code that I am working with: class Player implements OthelloPlayer { depth; constructor(depth: number) { this.depth = depth; } getMove(state: OthelloState) { return this.MinimaxDecision(stat ...

The operation failed with a TypeError because the object does not allow the addition of the newField property

I encountered an error that says: TypeError: Cannot add property newField, object is not extensible Whenever I try to add a new key or change a value, it doesn't work and I'm not sure what the issue is. dynamicFilter; public ionViewWillEnte ...

Revise Swagger UI within toggle button switch

My project aims to showcase three distinct OpenApi definitions within a web application, enabling users to explore different API documentation. The concept involves implementing a toggle button group with three buttons at the top and the Swagger UI display ...

Step-by-step guide on incorporating a climate clock widget into your Angular project

Is there a way to integrate the Climate Clock widget from into my Angular project? Upon adding the following code snippet: <script src="https://climateclock.world/widget-v2.js" async></script> <script src="https://climateclo ...

Show the key and value of a JSON object in a React component

When attempting to parse a JSON data file, I encountered an error message stating: "Element implicitly has an 'any' type because expression of type 'string' can't be used to the index type." The JSON data is sourced locally from a ...

Testing chai: verifying the inclusion of object types in an array

I am currently in the process of testing a Node.js/Typescript application. My goal is to have my function return an array consisting of objects. These objects should adhere to the following type: type myType = { title: string; description: string; ...

When using TypeScript with custom components as children in React, the `type` returned by React.Children is a string representing the function

It might sound a bit odd, or maybe I'm completely off track here. While going through some articles and React documentation on getting children and identifying specific child components using React.Component.map(), I ran into an issue with my custom c ...

The 'Content-Type' header cannot be defined for HTTP GET requests

I am currently working on setting up my GET requests to include the specific header: Content-Type: application/json Based on information from the documentation, I need to make the following adjustment: To customize these defaults, you can add or remov ...

Getting parameter names (or retrieving arguments as an object) within a method decorator in TypeScript: What you need to know

I am currently working on creating a method decorator that logs the method name, its arguments, and result after execution. However, I want to implement a filter that allows me to choose which parameters are logged. Since the number and names of parameter ...

What is the process for exporting all sub-module types into a custom namespace?

When we import all types from a module using a custom-namespace, it appears to work smoothly, for example: import * as MyCustomNamespace from './my-sub-module' We are also able to export all types from a module without creating a new namespace, ...

What is the best way to access values from dynamically added components in Svelte when using data from a REST API in a loop?

Previously, I posted this query but now I've made changes to utilize a REST service for retrieving the item list. Everything functions as expected when the data is hardcoded, however, I encounter undefined values when using data from the REST service. ...

Updating the state on change for an array of objects: A step-by-step guide

In my current scenario, I have a state variable defined as: const [budget, setBudget] = React.useState<{ name: string; budget: number | null }[]>(); My goal is to update this state by using a TextField based on the name and value of each input ...

Can you identify the category of the new Set containing the elements 1, 2, and 3?

As a beginner in TypeScript, I'm currently exploring the appropriate type for JavaScript's new Set([1, 2, 3]), but my search has been unsuccessful so far. For instance: const objNums: {[key: string]: number} = {one: 1, two: 2, three: 3}; const a ...

Learn how to open a component in a new browser tab using Angular from a different component

I wish to display the MapComponent in a new browser tab when a button in my AppComponent html file is clicked. Currently, when I click the button, the MapComponent opens in a new tab but it also displays the button. How can I configure it so that only the ...

The custom component is not updating the NgIf directive in HTML even though it receives a boolean variable

I am struggling with a custom component that includes an *ngIf in its view to handle a boolean variable, but for some reason the *ngIf directive is not working. Here is the code snippet: Component @Input('title') titleText; @Input('backButt ...

A more efficient method for defining and utilizing string enums in Typescript

enum PAGES { HOME = 'HOME', CONTACT = 'CONTACT', } export const links: { [key: string]: string } = { [PAGES.HOME]: '/home', [PAGES.CONTACT]: '/contact', }; export function getLink(page: string) { return B ...

Avoid retrieving information from Firestore

Hey everyone, I'm struggling to figure out why I can't retrieve data from Firestore. Even after carefully reading the documentation and double-checking the path, I still can't seem to make it work. I'm working with Ionic framework. getC ...

Exploring the differences between Typescript decorators and class inheritance

I find myself puzzled by the concept of typescript decorators and their purpose. It is said that they 'decorate' a class by attaching metadata to it. However, I am struggling to understand how this metadata is linked to an instance of the class. ...