Passing a generic type as a parameter in a generic class in TypeScript

TypeScript: I have a method in the DataProvider class called getTableData:

public static getTableData<T extends DataObject>(type: { new(): T}): Array<T> { ... }

Everything works fine when I use it like this:

let speakers = DataProvider.getTableData(Speaker);  // where Speaker is a class

Now I want to invoke this from a generic Class:

export class ViewModelBase<T extends DataObject> {   
  public getData(): Array<T> {
    return <T[]> DataProvider.getTableData(T);
  }
}

But now I am facing a Cannot find name 'T' error for the T parameter I pass to getTableData. How should I call getTableData?

Update: Thanks to @Paleo's assistance, I came up with this solution:

export class ViewModelBase<T extends DataObject> {   

  constructor(private dataObjectClass: { new(): T}){}

  public getTableData(): Array<T> {
    return <T[]> DataProvider.getTableData<T>(this.dataObjectClass);
  }
}

Even though in:

class SpeakerViewModel extends ViewModelBase<Speaker> { ... }
I specified that it is a ViewModel for Speaker, I still need to instantiate the SpeakerViewModel like:

let vm = new SpeakerViewModel(Speaker);

It seems like I still don't fully grasp this concept.

Answer №1

Metadata in generics is limited; they are not applicable as function parameters. Perhaps consider using the following approach:

export class BaseViewModel<T extends Entity> {
  constructor(private EntityClass: {new(): T}) {
  }
  public fetchData(): Array<T> {
    return DataHandler.fetchData<T>(this.EntityClass);
  }
}

Answer №2

Perhaps this explanation could be useful:

export abstract class BaseEntity {
  public static from<T extends BaseEntity>(c: new() => T, data: any): T {
    return Object.assign(new c(), data)
  }
  public static first<T extends BaseEntity>(c: new() => T, data) {
    if (data.rows.length > 0) {
      let item = data.rows.item(0);
      return BaseEntity.from(c, item);
    }
    return null;
  }

}

This base class is designed for extension, allowing methods to be called on either the base class or its subclasses.

For example:

return Product.first(Product, data);

Or:

return BaseEntity.first(Product, data);

Take note of how the from() method is utilized within the first() method.

Answer №3

Have you considered creating a base type and then extending it? By doing this, your function can accept the base type and you can call it with the extended type. For example:

export interface BaseData {
  key: object
}

After defining the base type:

import { BaseData } from 'baseDataFile'

export interface DerivedData extends BaseData {
  key: someObjectType
}

Now:

import { BaseData } from 'baseDataFile'

export const someFunc = (props: BaseData) => {
    // do something
    return result 
}

Finally:

import { DerivedData } from 'derivedDataFile'

const myData: DerivedData = something as DerivedData
const myNewData = someFunc(myData)

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

Adjusting the date in Angular 8 by increasing or decreasing it in the dd-MM-yyyy layout with a button press

How can I dynamically adjust the date in an input box by using buttons to increment and decrement it? Below is the code snippet: prev() { let diff = 1; //1 to increment and -1 to decrement this.date.setDate(this.date.getDate() - diff ...

TS: How can we determine the type of the returned object based on the argument property?

Assume we have the following data types type ALL = 'AA' | 'BB' | 'CC'; type AA = { a: number; }; type BB = { b: string; }; type CC = { c: boolean; }; type MyArg = { type: ALL }; I attempted to create a mapping between type n ...

Error occurs when using JSON.stringify with a Typescript array map

When running this code snippet in Typescript: [].map(JSON.stringify); An error is being thrown: Argument of type '{ (value: any, replacer?: ((key: string, value: any) => any) | undefined, space?: string | number | undefined): string; (value: a ...

Combining Vue with Typescript and rollup for a powerful development stack

Currently, I am in the process of bundling a Vue component library using TypeScript and vue-property-decorator. The library consists of multiple Vue components and a plugin class imported from a separate file: import FormularioForm from '@/FormularioF ...

Arranging strings in descending order using Typescript

I was attempting to arrange a string[] in a descending order. This is what I have come up with so far: let values = ["Saab", "Volvo", "BMW"]; // example values.sort(); values.reverse(); Although this method is effective, I am wondering if there is a mo ...

The quantity of elements remains constant in the EventEmitter

The Grid component is structured as follows: export class GridComponent { @Output('modelChanged') modelChangedEmitter = new EventEmitter(); private valueChanged(newValue: any, item: Object, prop: string) { item[prop] = newValue; ...

Error in React Typescript Order Form when recalculating on change

When creating an order form with React TypeScript, users can input the quantity, unit price, and select whether the item is taxable. In this simplified example, only 1 or 2 items can be added, but in the final version, users will be able to add 10-15 item ...

The error message "Property 'value' is not present on type 'EventTarget & HTMLSelectElement'" indicates that the 'value' property is not recognized on the Event

Here is the code snippet that I am working with: interface IHandleSelection { (value: string): any | void; } interface IPipeChangeEventValueToFunction { (handler: IHandleSelection): (event: React.ChangeEvent<HTMLSelectElement>) => void; ...

JavaScript: specify parameters for function inputs

I'm curious about optimizing Javascript/Typescript functions arguments for clean code. To demonstrate, let's consider a basic example. Imagine I have a React component with a view property as props: <Grid view="Horizontal" /> ty ...

Is it possible to obtain the return type of every function stored in an array?

I'm currently working with Redux and typesafe-actions, and I am trying to find a way to automatically generate types for the actions in my reducer. Specifically, I want to have code completion for each of the string literal values of the action.type p ...

AmplifyJS is throwing an error: TypeError - It seems like the property 'state' is undefined and cannot be read

I am currently working on integrating the steps outlined in the Amplify walkthrough with an Angular cli application. My app is a brand new Angular cli project following the mentioned guide. My objective is to utilize the standalone auth components a ...

Revamp the switch-case statement in JavaScript code

Is there a way to refactor this code in order to prevent repeating dailogObj.image? I would have used a return statement if it wasn't for case 5 where two assignments are required. getDialogData(imageNum): any { const dailogObj = { image: ...

Seems like ngAfterViewInit isn't functioning properly, could it be an error on my end

After implementing my ngAfterViewInit function, I noticed that it is not behaving as expected. I have a hunch that something important may be missing in my code. ngOnInit() { this.dataService.getUsers().subscribe((users) => {this.users = users) ; ...

Tips for showcasing saved images in Spring Boot with Angular 4

I am currently utilizing Spring Boot in combination with Angular 4. The issue I am facing involves uploading an image to the project location. However, upon attempting to view the uploaded image, it does not display correctly and instead throws an error. H ...

How can the panel within an accordion be enlarged or minimized?

Currently, I am implementing an accordion feature with the option to expand or collapse all panels using two buttons. My goal is to allow users to manage each panel within the accordion individually. However, I have encountered an issue that needs attenti ...

The data type of the element is implicitly set to 'any' due to the fact that a 'string' expression cannot be used to reference the type '(controlName: string) => boolean'

checkError(typeofValidator: string, controlName: string): boolean { return this.CustomerModel.formCustomerGroup.contains[controlName].hasError(typeofValidator); } I am currently learning Angular. I came across the same code in a course video, but it i ...

Expand the font manually

Is there a way to define a type that represents the widened version of another type? Consider the following scenario: function times<A extends number, B extends number>(a: A, b: B): A & B; The intention behind this times function is to preserv ...

What are the steps for encountering a duplicate property error in TypeScript?

I'm currently working with typescript version 4.9.5 and I am interested in using an enum as keys for an object. Here is an example: enum TestEnum { value1 = 'value1', value2 = 'value2', } const variable: {[key in TestEnum]: nu ...

Struggling to connect the array of objects from the .ts file with the template (.html) in Angular

Inside this .ts file, I am populating the "mesMenus" array that I want to display in the .html file: export class MenusComponent{ mesMenus= new Array<Menu>(); constructor(private gMenuService:GestionMenuService){ this.gMenuService.onAdd ...

Incorporating timed hover effects in React applications

Take a look at the codesandbox example I'm currently working on implementing a modal that appears after a delay when hovering over a specific div. However, I've encountered some challenges. For instance, if the timeout is set to 1000ms and you h ...