TypeScript: self-referencing return type for static methods in inheriting classes

This is doable in TypeScript 2.0+. By using an inline { new(): T } type to capture this, you'll get what you wanted:

type Constructor<T> = { new (): T }

class BaseModel {
  static getAll<T>(this: Constructor<T>): T[] {
    return [] // dummy impl
  }

  /**
   * Example of static method with an argument:
   */
  static getById<T>(this: Constructor<T>, id: number): T | undefined {
    return // dummy impl
  }

  save(): this {
    return this // dummy impl
  }
}

class SubModel extends BaseModel {}

const sub = new SubModel()
const savedSub: SubModel = sub.save()

// Behold: SubModel.getAll() returns SubModels, not BaseModel
const savedSubs: SubModel[] = SubModel.getAll()

Note that getAll still expects no arguments with this typing.

For more information, see https://www.typescriptlang.org/docs/handbook/generics.html#using-class-types-in-generics and https://stackoverflow.com/a/45262288/1268016


Based on the simplest answer to the GitHub issue, you can use InstanceType<> like this:

class Foo {
    static create<T extends typeof Foo>(this: T): InstanceType<T> {
        return new this() as InstanceType<T>
    }

    static getAll<T extends typeof Foo>(this: T): Array<InstanceType<T>> {
        return []
    }
}

class Bar extends Foo { }

const a = Bar.getAll() // typeof a is Bar[]
const b = Bar.create() // typeof b is Bar.

Where I threw in the create function just for illustration, from the linked GitHub example.