Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript: pass generic type as parameter in generic class

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

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

this works perfectly when I code:

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

now I want to call this from a generic Class:

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

Now I get a Cannot find name 'T' error for the T parameter I pass to getTableData. How should getTableData be called?

update: With the help of @Paleo I came up this:

export class ViewModelBase<T extends DataObject> {   

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

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

the thing is that although I have already told in: class SpeakerViewModel extends ViewModelBase<Speaker> { ... } that I want it to be a ViewModel for Speaker I still have the instantiate the SpeakerViewModel like:

let vm = new SpeakerViewModel(Speaker);

although I have already told it is all about Speaker. I guess I still don't fully understand this.

like image 234
Bronco Oostermeyer Avatar asked May 27 '16 11:05

Bronco Oostermeyer


2 Answers

Generics are just metadata. They cannot be used as parameters when calling a function. Maybe you need something like this:

export class ViewModelBase<T extends DataObject> {
  constructor(private Cl: {new(): T}) {
  }
  public getData(): Array<T> {
    return DataProvider.getTableData<T>(this.Cl);
  }
}
like image 144
Paleo Avatar answered Sep 29 '22 12:09

Paleo


maybe this would help:

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 class can be extended by others so you could call methods on the base class or on its subclasses.

For instance:

return Product.first(Product, data);

Or:

return BaseEntity.first(Product, data);

See how from() method is called from inside first()

like image 40
flags Avatar answered Sep 29 '22 12:09

flags