Factory returning classes in TypeScript

How about something like:

export interface Base {}

export interface IA extends Base {
    value: string;
}

export type Builders = {
    [name: string]: { new <T extends Base>(): T };
}

export function factory(foo: string): Builders {
    class A implements IA {
        value:string = foo + '-A';
    }

    return { A };
};

And:

import { factory, IA, Builders } from './Factory';

export default class Main {
    private inner: Builders;

    constructor(foo:string) {
        this.inner = factory(foo);
    }

    get a():IA {
        return new this.inner.A() as IA;
    }
}

Edit

What's wrong with this as factory.ts:

export class Base {}

export type Builders = {
    [name: string]: { new <T extends Base>(): T };
}

class A extends Base {
    value: string;

    constructor();
    constructor(foo: string);
    constructor(foo?: string) {
        super();
        this.value = foo + "-A";
    }
}

// more classes...

export function factory(foo: string): Builders {
    return { A: A.bind(A, foo) };
};

It's basically the same as what you did, just that the classes are not defined inside the class, and are exported so no need for the interfaces I suggested.
Also, this way all the classes will only be evaluated once and not every time the factory function is invoked.


Your code (the OP's) is working just fine in July 2019 with Typescript 3.5.2.

PS. I got here when I was trying to create a Class Factory in Typescript.

Things to keep in mind:

  1. The concept of Class definition in Typescript has two folds. One is the instance type, and the other one is the constructor function. (source in TS Docs)
  2. Since Typescript 2.8 released in March 2018, you can explicitly create the instance type from the constructor function using InstanceType. e.g. type classType = InstanceType<typeof C>. This should make the explicit type definition in the selected answer simpler.
  3. Finally, I got my code working using a simple trick as following:
export default class MyNewClass
   extends ClassFactory("custom param1") {}

This way I am actually defining the generated class as a new class by itself, so both the constructor function and the instance-type type are going to be implicitly created and will be valid. And I don't need to explicitly define the two separately.