Bronco Oostermeyer
Bronco Oostermeyer

Reputation: 580

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.

Upvotes: 16

Views: 53743

Answers (3)

glowkeeper
glowkeeper

Reputation: 259

How about defining a base type and extending it? Then your function could expect the base type, and you could call it with the extended type. e.g:

export interface BaseData {
  key: object
}

Then:

import { BaseData } from 'baseDataFile'

export interface DerivedData extends BaseData {
  key: someObjectType
}

Now:

import { BaseData } from 'baseDataFile'

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

Finally:

import { DerivedData } from 'derivedDataFile'

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

Upvotes: -2

flags
flags

Reputation: 511

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()

Upvotes: 3

Paleo
Paleo

Reputation: 23692

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);
  }
}

Upvotes: 6

Related Questions