Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Referencing class without name to use different static method in subclasses in TypeScript

In ES6, you can reference static methods via this.constructor:

class MainClass {
  static info() {
    return "This is some information";
  }
  constructor() {
    this.info = this.constructor.info(); // Allows subclass to define different '.info()' method.
  }
}

class ChildClass extends MainClass {
  static info() {
    return "This information is from the child";
  }

  constructor() {
    super();
  }
}

Is there a way to do this in TypeScript? I want to be able to override the super class's static method and use it from the subclass without redefining the reference in an instance method. Right now, the only way I know how to access a static method in TypeScript uses the class name.

MainClass.info();

But if I do that, the subclass will continue to use MainClass.info(); rather than it's own .info() method.

like image 325
Shaun Avatar asked Jun 09 '16 13:06

Shaun


2 Answers

How about this:

interface MainClassConstructor {
    new (): MainClass;
    info(): string;
}

class MainClass {
    static info() {
        return "This is some information";
    }

    private info: string;

    constructor() {
        this.info = (this.constructor as MainClassConstructor).info(); // Allows subclass to define different '.info()' method.
    }
}

class ChildClass extends MainClass {
    static info() {
        return "This information is from the child";
    }

    constructor() {
        super();
    }
}

(code in playground)


Edit

You can also use typeof MainClass instead of the MainClassConstructor interface I added:

class MainClass {
    static info() {
        return "This is some information";
    }

    private info: string;

    constructor() {
        this.info = (this.constructor as typeof MainClass).info(); // Allows subclass to define different '.info()' method.
    }
}

In addition there's a discussion/suggestion of having this.constructor returning the right type here: T.constructor should be of type T.

Another option is to use method overriding:

class MainClass {
    private info: string;

    constructor() {
        this.info = this.getInfo();
    }

    protected getInfo(): string {
        return "This is some information";
    }
}

class ChildClass extends MainClass {
    constructor() {
        super();
    }

    protected getInfo(): string {
        return "This information is from the child";
    }
}
like image 161
Nitzan Tomer Avatar answered Oct 19 '22 20:10

Nitzan Tomer


Checkout this typescript code:

class MainClass {
  static info() {
    return "This is some information";
  }
  info: string;

  constructor() {
    this.info = (this.constructor as any).info(); // Allows subclass to define different '.info()' method.
  }
}

class ChildClass extends MainClass {
  static info() {
    return "This information is from the child";
  }

  constructor() {
    super();
  }
}

If compilation target is ES6 this compiles to exaclty the code you gave above and works fine. It also works fine if it is compiled down to ES5.

Note that I used a as any hack to allow calling .info() on the constructor function.

Alternatively, you could overwrite the setting of this.info in each child class. This way you wouldn't need the hack.

like image 34
dpoetzsch Avatar answered Oct 19 '22 18:10

dpoetzsch