What is the process of generating an instance from a generic type in TypeScript?

Managing data in local storage and making remote API queries are two crucial aspects of my service. When defining a data model, I specify whether it should utilize local storage or the remote API.

Currently, I am working on creating a proxy service that can dynamically choose between fetching data from local storage or the remote API based on the model definition.

This is the code I have so far:

export class ProxyService<T> {
  public type: new () => T;
  private emptyModel: T = new this.type();
  private localstorageService: LocalstorageDataService<T> =
    new LocalstorageDataService(this.type, this.httpClient);
  private remoteDataService: RemoteDataService<T> = new RemoteDataService(this.type, this.httpClient);

  constructor(
    private httpClient: HttpClient,
  ) { }

  getOne(id: number): Observable<T> {
    if (this.emptyModel.use_localstorage) {
      return of(this.localstorageService.findById(id));
    } else {
      return this.remoteDataService.getOne(id).pipe(map((result: T) => result));
    }
  }

  // other proxy functions are here...
}

However, I encounter the following error:

Error: Uncaught (in promise): TypeError: this.type is not a constructor
TypeError: this.type is not a constructor
    at new ProxyService (proxy.service.ts:19)

Since both RemoteDataService and LocalstorageDataService require a model, it makes sense to define one in the ProxyService, which is used throughout the project with various models.

The error seems to originate from line 19, which is:

private emptyModel: T = new this.type();

I attempted to resolve it in the constructor:

export class ProxyService<T> {
  // ...
  constructor(
    public type: new () => T;
    private httpClient: HttpClient,
  ) { }
  // ...

However, this approach requires me to specify a model when calling the ProxyService, which is not ideal. I want to use the ProxyService as shown below:

export class HelperService<T> {
  constructor(
    private proxy: ProxyService<T>,
  ) { }

Do you have any suggestions on how I can resolve this issue?

Answer №1

It appears that there is some confusion between TypeScript type annotations and actual JavaScript implementations during runtime.

In TypeScript, you are unable to instantiate a new object using new T() because T is simply a type annotation without a concrete implementation.

Since your type field is undefined, attempting to create a new instance with

private emptyModel: T = new this.type();
will result in failure.

It seems you were on the right track with your solution.

Instead of creating the Proxy class as a singleton, consider making it a regular class.

Then, create a service that offers a factory method for generating instances.

export class ProxyFactoryService {

    constructor(private httpClient: HttpClient) { }

    proxyFactory<T>(newable: new() => T) {
      const instance = new newable(); 
      return new ProxyService<T>(this.httpClient, instance);
    }
}

Your ProxyService can take a form similar to the following:

 export class ProxyService<T> {
   private localstorageService: LocalstorageDataService<T>;
   private remoteDataService: RemoteDataService<T>;

   constructor(private httpClient: HttpClient, private instance: T) {
     this.localstorageService = new LocalstorageDataService(this.instance, this.httpClient);
     this.remoteDataService = new RemoteDataService(this.instance, this.httpClient)
   }

   getOne(id: number): Observable<T> {
     if (this.instance.use_localstorage) {
       return of(this.localstorageService.findById(id));
     } else {
       return this.remoteDataService.getOne(id).pipe(map((result: T) => result));
    }
  }
  // other proxy functions are here...
}

To utilize this setup:

constructor(private proxyService: ProxyService) {}

ngOnInit() {
  const proxy = this.proxyService.proxyFactory(SomeClass);
  proxy.getOne(...);
}

Always question how things would function without annotations.

When TypeScript compiles, all type annotations vanish as they are solely for design time static type checking.

Another perspective is simplifying the approach by removing generics and using concrete types, ultimately achieving what you aimed for:

const s: new () => String;
const i = new s();

Here, s is a constructor that returns a type of String. The issue arises because s is undefined, although we know what it should be. This may seem convoluted, but hopefully, it clarifies the concept.

Looking at the compiler output, it becomes evident why the previous code won't function:

const s;
const i = new s();

Thankfully, TypeScript will catch this error before the code runs. A properly configured IDE should provide notifications and errors during design time.

Realizing the differences can be perplexing, particularly for individuals transitioning from languages like C# and Java where the CIL/CLR handles static typing. In TypeScript, there is no runtime environment, just compilation to JavaScript.

Static typing and type annotations do not exist during runtime.

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

Is it possible to define a shared function for enums in TypeScript?

I have created an enumeration called VideoCategoryEnum: enum VideoCategoryEnum { knowledge = 0, condition = 1, interview = 2, speech = 3, entertainment = 4, news = 5, advertisement = 6, others = 7, } I am looking to implement a shared met ...

Sort through the files for translation by utilizing a feature within Typewriter

I am looking to implement Typewriter in a project that involves translating many C# files into TypeScript using WebEssentials. Is there a way to configure the template so that only class files containing a specific attribute are translated in this mann ...

Error in React: Trying to access property 'functionName' of an undefined object on click event

I am facing an issue while trying to click a button in my React component that is supposed to trigger a function with a parameter named "item" which is defined within the function. The pseudo-HTML snippet for this scenario looks like: <div>{item.cre ...

What steps can be taken to ensure that the requestAnimationFrame function does not redraw the canvas multiple times after a button click?

I am currently working on a project where I am drawing a sin wave on a canvas and adding movement to it. export class CanvasComponent implements OnInit { @ViewChild('canvas', { static: true }) canvas: ElementRef<HTMLCanvasElement>; ...

Encountered an issue in React and Typescript where the argument type is not compatible with the parameter type 'EventListenerOrEventListenerObject'

One challenge I am facing is integrating Typescript into my React project: componentDidMount() { document.addEventListener('mousemove', this.handleMouseMove); } private handleMouseMove = (e: React.MouseEvent<HTMLElement>) => { appS ...

get a duplicate of an object

Is this the proper method for creating a duplicate of an object? class ObjectWrapper { private _obj; /*** * Copy object passed as argument to this._obj */ constructor (_obj: Object) { this._obj = _obj; } /** Return copy of this._ ...

Creating alerts in Angular using EventEmitter

I am in the process of building an Angular application and I have a requirement to implement alerts. These alerts should be displayed in response to POST/PUT/DELETE requests, showing a success message. Previously, I achieved this by creating a class: expo ...

The functionality of the String prototype is operational in web browsers, but it encounters issues

Version: 8.1.0 The prototype I am working with is as follows: String.prototype.toSlug = function () { return (<string>this) .trim() .toLowerCase() .replace(/\s+/g, '-') .replace(/[^\w\-]+/g, '') ...

Issue detected in React Rollup: the specific module 'name' is not being exported from the node_modules directory

Currently in the process of creating a library or package from my component. The tech stack includes React, Typescript, and various other dependencies. Encountering an error while using Rollup to build the package: [!] Error: 'DisplayHint' is ...

Navigating SSL certificate prompts in Protractor

Our programs utilize SSL certificates and we are unable to bypass Chrome's prompt for selecting a certificate. We would be satisfied with simply choosing the one certificate needed. Attempts have been made using this code: capabilities: { browser ...

What is the TypeScript syntax for indicating multiple generic types for a variable?

Currently working on transitioning one of my projects from JavaScript to TypeScript, however I've hit a roadblock when it comes to type annotation. I have an interface called Serializer and a class that merges these interfaces as shown below: interfa ...

TypeScript and Express create a powerful array combination capability within the type system

After defining the EventType as either "TYPE A" or "TYPE B", I am looking to create a type for an array that can only contain one or both of these event types. Simply typing it as an EventType[] allows duplicates, which is not ideal. type Test = EventType ...

Angular 14 now offers ngx-pinch-zoom for an enhanced zooming experience

Is it possible to add ngx-pinch-zoom to an Angular 14 project? I encountered a peer dependency conflict when trying to install pinch-zoom with --legacy-peer-deps, which worked in the project but failed in the ci/cd pipeline due to the conflict. I attempt ...

What is the best way to represent a state with two possible fields in React using TypeScript?

There is a specific state item that can have its own value or reference another item using an ID. interface Item { itemName: string; itemValue: { valLiteral: number } | { idNumber: string }; } const indItem1: Item = { itemName: "first sample&quo ...

What could be causing the transparency of my buttons when viewed on my device?

Recently, I customized the appearance of buttons in my App by adding colors. Surprisingly, everything looks perfect when I test it on a local server on my PC. However, once I deploy the App to my Android device, all the buttons become transparent. In my v ...

A step-by-step guide on configuring data for aria's autocomplete feature

Currently, I am implementing aria autocomplete and facing an issue while trying to populate data from the server into the selection of aria autocomplete. I have tried setting the selected property of the aria autocomplete object, but it doesn't seem t ...

SonarQube alerting you to "Eliminate this unnecessary casting"

Can someone help me understand why SonarQube is flagging this error and suggest a resolution? The unnecessary cast should be removed. Promise.all([ this.customerViewCmr4tProvider.getData(activeNumber), this.customerBillManagementProvider.getData(ind ...

How can I provide type annotations for search parameters in Next.js 13?

Within my Next.js 13 project, I've implemented a login form structure as outlined below: "use client"; import * as React from "react"; import { zodResolver } from "@hookform/resolvers/zod"; import { signIn } from "n ...

Having trouble extracting a list of matches using a Regular Expression?

const stringWithDate: string = "4/7/20 This is a date!"; const reg: RegExp = new RegExp("^(\d{1,2}\/\d{1,2}\/\d{1,2})").compile(); const exist: boolean = reg.test(stringWithDate) const matches: RegExpExecArray | null = reg.exec(str ...

Error message in Ionic 2: "Property is not found on type"

Currently, I am working on a project in Ionic 2 and have encountered a stumbling block with a seemingly simple task. My issue lies with a Textbox where I aim to input text that will then be displayed. I found some code on a website (http://www.tizag.com/j ...