I am trying to instantiate a child class from a static method in a base class. I want to type my base class correctly rather than using any
as the return type on all my static methods. I tried the solution here but it doesn't work for a static method that references other static methods, or accepts arguments. How can I correctly inherit from a base class in typescript, and still reference other methods and accept arguments?
class BaseClass {
id: string;
[key: string]: unknown;
static getName() {
return this.name.toUpperCase()
}
static async find<T extends BaseClass>(this: new (...args: any[]) => T, id: string)
: Promise<T> {
const tableName = this.getName();
const result: GetResult = db.find(tableName, id);
return new this(result);
}
}
class Child extends BaseClass {
name: string;
static findOne(id: string): Promise<Child> {
return this.find(id);
}
}
Child.find('abcd');
This causes two different errors
Property 'getName' does not exist on type 'new (...args: any[]) => T'.
(in the find
method)Type 'BaseModel' is missing the following properties from type 'Child': name.
(in the return type for findOne
method)In find
method of the base class you should specify that it expects child class to implement static getName
method, like this:
static async find<T>(this: { new (arg: GetResult): T } & typeof BaseClass, id: string): Promise<T>
Particularly { new (arg: GetResult): T }
brings you constructor and typeof BaseClass
brings you static members.
I mocked some missing parts and it typechecks.
type GetResult = string;
const db = {
find: (a: string, b: string) => "bar",
}
class BaseClass {
id: string = "bzzzz";
[key: string]: unknown;
static getName() {
return 'NAME'
}
static async find<T>(this: { new (arg: GetResult): T } & typeof BaseClass, id: string)
: Promise<T> {
const tableName = this.getName();
const result: GetResult = db.find(tableName, id);
return new this(result);
}
}
class Child extends BaseClass {
name: string = "Child";
static findOne(id: string): Promise<Child> {
return this.find(id);
}
}
Child.find('abcd');