Home > Mobile >  Typescript, cleaner way to target a generic class method
Typescript, cleaner way to target a generic class method

Time:12-22

Let's consider the following code:

export class BaseClass<T> {
  property = this.buildProperty();

  buildProperty(){
    return someBuilder<T>();
  }
}

TS will magically infer the type of property using the returned type of buildProperty()

Now for a cleaner code, I would like to build the property within the constructor, I refactored the code as follows:

export class BaseClass<T> {
  property: ReturnType<BaseClass<T>['buildProperty']>;

  constructor(){
    this.property = this.buildProperty();
  }

  buildProperty(){
    return someBuilder<T>();
  }
}

Which is correct, however I'm not satisfied in repeating the current class type twice i.e. BaseClass<T>

I am then wondering if I could simplify the line using this. I tried rewriting the property's type as follow but had no success:

property: ReturnType<this['buildProperty']>;

Is there a cleaner way to achieve it ?

CodePudding user response:

You can extract the type of the buildProperty method by using the Type utility type from the TypeScript library.

You can use it as follows:

export class BaseClass<T> {
  property: ReturnType<BaseClass<T>['buildProperty']>;

  constructor(){
    this.property = this.buildProperty();
  }

  buildProperty(){
    return someBuilder<T>();
  }
}

type BuildPropertyType = Type<typeof BaseClass>['prototype']['buildProperty'];

export class DerivedClass<T> extends BaseClass<T> {
  property: ReturnType<BuildPropertyType>;

  constructor() {
    super();
    this.property = this.buildProperty();
  }
}

This way you can extract the type of buildProperty and use it to define the type of the property in the derived class, without repeating the type of the base class.

Note that Type is a utility type from the TypeScript library, which is available in TypeScript 3.7 and above.

CodePudding user response:

One can simply use ReturnType<typeof this.buildProperty>

// silly function returning a different type then T (here just T | string for the example)
function someBuilder<T>(): T | string{
  return {} as unknown as T | string;
}

export class BaseClass<T> {
  property: ReturnType<typeof this.buildProperty>;

  constructor(){
    this.property = this.buildProperty();
  }

  buildProperty(){
    return someBuilder<T>();
  }
}

const test = new BaseClass<number>();
test.property // is number | string
  • Related