13

Is it possible to get the parent class of a TypeScript class at runtime? I mean, for example, within a decorator:

export function CustomDecorator(data: any) {
  return function (target: Function) {
    var parentTarget = ?
  }
}

My custom decorator is applied this way:

export class AbstractClass {
  (...)
}

@CustomDecorator({
  (...)
})
export class SubClass extends AbstractClass {
  (...)
}

Within the decorator, I would like to have an instance to AbstractClass.

Thanks very much for your help!

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360

2 Answers2

15

You can use the Object.getPrototypeOf function.

Something like:

class A {
    constructor() {}
}

class B extends A {
    constructor() {
        super();
    }
}

class C extends B {
    constructor() {
        super();
    }
}

var a = new A();
var b = new B();
var c = new C();

Object.getPrototypeOf(a); // returns Object {}
Object.getPrototypeOf(b); // returns A {}
Object.getPrototypeOf(c); // returns B {}

Edit

After the code @DavidSherret added (in a comment), here's what you want (I think):

export function CustomDecorator(data: any) {
  return function (target: Function) {
    var parentTarget = target.prototype;
    ...
  }
}

Or as @DavidSherret noted:

function CustomDecorator(data: any) {
  return function (target: Function) {
    console.log(Object.getPrototypeOf(new (target as any)));
  }
}

2nd Edit

Ok, so here's what I hope to be you goal:

function CustomDecorator(data: any) {
    return function (target: Function) {
        var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
        console.log(parentTarget === AbstractClass); // true :)
    }
}
Community
  • 1
  • 1
Nitzan Tomer
  • 155,636
  • 47
  • 315
  • 299
  • I don't think this works inside the decorator function – David Sherret Apr 26 '16 at 14:14
  • Why not? Should work the same regardless of the scope it's in.. Can you supply the code? maybe a link to Playground? – Nitzan Tomer Apr 26 '16 at 14:16
  • [see here](http://www.typescriptlang.org/play/#src=function%20CustomDecorator(data%3A%20any)%20%7B%0D%0A%20%20return%20function%20(target%3A%20Function)%20%7B%0D%0A%09console.log(target)%3B%0D%0A%20%20%09console.log(Object.getPrototypeOf(target))%3B%0D%0A%20%20%7D%0D%0A%7D%0D%0A%0D%0Aclass%20AbstractClass%20%7B%0D%0A%20%20name%3A%20string%3B%0D%0A%7D%0D%0A%0D%0A%40CustomDecorator(%7B%7D)%0D%0Aclass%20SubClass%20extends%20AbstractClass%20%7B%0D%0A%0D%0A%7D) -- oh wait, i just realized this solution is dealing with instances instead of the function directly – David Sherret Apr 26 '16 at 14:18
  • Yeah, just need to [create an instance first](http://www.typescriptlang.org/play/#src=function%20CustomDecorator(data%3A%20any)%20%7B%0D%0A%20%20return%20function%20(target%3A%20Function)%20%7B%0D%0A%20%20%09console.log(Object.getPrototypeOf(new%20(target%20as%20any)))%3B%0D%0A%20%20%7D%0D%0A%7D%0D%0A%0D%0Aclass%20AbstractClass%20%7B%0D%0A%20%20name%3A%20string%3B%0D%0A%7D%0D%0A%0D%0A%40CustomDecorator(%7B%7D)%0D%0Aclass%20SubClass%20extends%20AbstractClass%20%7B%0D%0A%0D%0A%7D) – David Sherret Apr 26 '16 at 14:22
  • @DavidSherret. Oh, right, cuz you get the constructor. in that case should be easy. revised answer. – Nitzan Tomer Apr 26 '16 at 14:23
  • 1
    oh wow, yeah doing `target.prototype` is definitely the better way. Seems pretty obvious now that you pointed it out haha. I think it would be good to update the answer to just have `target.prototype` to cut to the chase... no need to list the `Object.getPrototypeof(new ...)` solution because that can have issues when the constructor expects parameters – David Sherret Apr 26 '16 at 14:25
  • @DavidSherret It's another option, and maybe the OP will find it more suited for his needs (or future readers) so I tend towards keeping it, but if you'd like I'll remove it from the answer. – Nitzan Tomer Apr 26 '16 at 14:37
  • Thanks guys for your help! Unfortunately the protytotype isn't exactly the class :-( The prototype corresponds to the constructor function associated with the class. In my use case, the parent class is decorated and metadata are set on it using reflect-metadata. But these metadata aren't present on this constructor function. See this plunkr: https://plnkr.co/edit/A2Gcs2MGULZ7Bn1xBEFN?p=preview. – Thierry Templier Apr 26 '16 at 15:23
  • @ThierryTemplier Can you maybe write up a short code example in Playground so I may see exactly what's up? That plnkr is too much to deal with. – Nitzan Tomer Apr 26 '16 at 15:37
  • @NitzanTomer perhaps this one: http://www.typescriptlang.org/play/#src=function%20CustomDecorator(data%3A%20any)%20%7B%0D%0A%20%20return%20function%20(target%3A%20Function)%20%7B%0D%0A%09console.log(target)%3B%0D%0A%20%20%09console.log(Object.getPrototypeOf(target))%3B%0D%0A%20%20%7D%0D%0A%7D%0D%0A%0D%0Aclass%20AbstractClass%20%7B%0D%0A%20%20name%3A%20string%3B%0D%0A%7D%0D%0A%0D%0A%40CustomDecorator(%7B%7D)%0D%0Aclass%20SubClass%20extends%20AbstractClass%20%7B%0D%0A%0D%0A%7D. ;-) – Thierry Templier Apr 26 '16 at 15:57
  • The problem is that `target.prototype === AbstractClass` returns false – Thierry Templier Apr 26 '16 at 15:58
  • 1
    @ThierryTemplier check out my 2nd edit of the answer – Nitzan Tomer Apr 26 '16 at 16:08
  • Umm, `Object.getPrototypeOf(target.prototype).constructor;` is actually just a complicated way of saying `Object.getPrototypeOf(target);`. Is there any point to not just getting the base constructor directly like that? – AnorZaken Oct 24 '22 at 00:18
0

For me following construct worked for getting base type constructor from a type constructor:

class Validator {
    constructor(private readonly ctr: ConstructorFunction<T>) {
        this.id = ctr.name;
        //...
        let protoRef = ctr['__proto__'] as Function;
        this._inheritFrom = protoRef && protoRef !== Object ? protoRef.name : null;
        this._inheritsFromValidator = null;
        //...
    }
}

Yeah this is not sound as fancy as smth as ctr.getBaseClassConstructor() a-la

type BaseType<T> = [some-magic]<T>
function getBasicType<T>():BaseType<T>;

but that trick with __proto__ work.

Kote Isaev
  • 273
  • 4
  • 13