Create instance from base class and maintain typings

Answer

Based on @Titian’s answer here, you need to make your findRecord method into a generic function where T describes the specific class instance. You use a this argument as an ignored first argument so that typescript can infer the type of T based on the value of this when you call it.

abstract class MyRecord {

    constructor(id: number) {
    }

    static findRecord<T>(this: new (id: number) => T, id: number): T {
        return new this(id);
    }
}

Typescript Playground Link

An Alternative Approach

Personally I have bought into the “inheritance is bad” mantra so I would move shared static logic into a separate class which can be instantiated for each record type by passing that record’s class as an argument to the constructor.

class RecordFinder<T extends BaseRecord> {

    private readonly recordClass: RecordConstructor<T>;

    constructor( recordClass: RecordConstructor<T> ) {
        this.recordClass = recordClass;
    }

    find(id: number): T {
        return new this.recordClass(id);
    }
}

interface BaseRecord {
    id: number;
}

type RecordConstructor<T extends BaseRecord> = new (id: number) => T;

Here I am restricting the type of recordClass based on an interface, so it doesn’t matter whether MyNode extends MyRecord or not.

const nodeFinder = new RecordFinder(MyNode);

const node = nodeFinder.find(1);

Typescript Playground Link

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top