styliss
styliss

Reputation: 269

Typescript Self Reference as Class Constructor

class Foo<T> {
    remake(){
        return new Foo<T>;
    }
    recast(){
        return this as any as Foo<Array<T>>
    }
}

I want to make Child class of Foo Class. Child class should be referencing itself on remake and recast

also, If there has other syntax for change to generics of instance, it will be good to me.

Upvotes: 0

Views: 1125

Answers (1)

Matt McCutchen
Matt McCutchen

Reputation: 30929

You can implement remake using this.constructor and type it using the this type. recast needs higher-kinded types or a way of faking them, as below, and needs you to explicitly specify the type constructor for each subclass (it might be possible to infer this automatically with a native implementation of higher-kinded types).

// Matt's mini "type functions" library

const INVARIANT_MARKER = Symbol();
type Invariant<T> = { [INVARIANT_MARKER](t: T): T };

interface TypeFuncs<C, X> {}

const FUN_MARKER = Symbol();
type Fun<K extends keyof TypeFuncs<{}, {}>, C> = Invariant<[typeof FUN_MARKER, K, C]>;

const BAD_APP_MARKER = Symbol();
type BadApp<F, X> = Invariant<[typeof BAD_APP_MARKER, F, X]>;
type App<F, X> = [F] extends [Fun<infer K, infer C>] ? TypeFuncs<C, X>[K] : BadApp<F, X>;

// Example

const F_Foo = Symbol();
type F_Foo = Fun<typeof F_Foo, never>;
const F_Bar = Symbol();
type F_Bar = Fun<typeof F_Bar, never>;
interface TypeFuncs<C, X> {
    [F_Foo]: Foo<X>; 
    [F_Bar]: Bar<X>;
}

class Foo<T, F = F_Foo> {
    remake(): this {
        return new (<any>this.constructor)();
    }
    recast(): App<F, T[]> {
        return this as any as App<F, T[]>;
    }
}
class Bar<T, F = F_Bar> extends Foo<T, F> { }

let b = new Bar<number>();
let b2 = b.remake();
console.log(b2.constructor.name);  // Bar
let b3 = b.recast();  // Bar<number[]>

Upvotes: 2

Related Questions