lilezek lilezek - 1 year ago 84
TypeScript Question

Accessing static member of generic class from a decorator

I have a decorated class:

@Decorator
class Entity {
public static member: string[] = [];
}


With a decorator:

function Decorator<T extends { new(...args: any[]): Entity }>(constructor: T) {
return class extends constructor {
constructor(...args: any[]) {
super(...args);
// Do some things
constructor.prototype.member.map((v: string) => {
// Do things with the elements of the static array.
});
}
};
}


Although this works, by using
constructor.prototype
which is of type
any
I lose the typechecking of
member
that is already in the prototype as an array of strings.

Is there a solution without losing the typechecking?

Edit: I've tested also:

function Decorator<T extends { prototype: typeof Entity; new(...args: any[]): Entity; }>(constructor: T) {
return class extends constructor {
constructor(...args: any[]) {
super(...args);
// Do some things
constructor.prototype.member.map((v) => {
// Do things with the elements of the static array.
});
}
};
}


but this gives an error in the line
@Decorator
:


Property 'prototype' is missing in type 'Entity'.'


Edit2: I've tested too:

function Decorator<T extends typeof Entity>(constructor: T) {
// This works and returns an Entity.
const x = new constructor({} as any);
// This doesn't work. Tsc says: 'Type 'T' is not a constructor function type.'
return class extends constructor {
constructor(...args: any[]) {
super(...args);
// This now works:
constructor.member.map((v) => {
// ...
});
}
};
}


but this gives an error in the line
@Decorator
:


Property 'prototype' is missing in type 'Entity'.'

Answer Source

You can do this:

(constructor.prototype as typeof Entity).member...

Then you'll have type safety, for example:

(constructor.prototype as typeof Entity).member2..

Will result in:

Property 'member2' does not exist on type 'typeof Entity'.


Edit

You can't do that.
Static memebers/functions are not part of the prototype, to take what you wanted to do, it should look like this:

function Decorator<T extends { prototype: Entity; new(...args: any[]): Entity; }>(constructor: T) { ... }

(difference is prototype: Entity and not typeof Entity), then the error you received will go away.
But, then you'll get the error that:

Property 'member' does not exist on type 'Entity'

Because it's a static member.

It's easy to see in the compiled js of the Entity class:

var Entity = (function () {
    function Entity() {
    }
    return Entity;
}());
Entity.member = [];

Clearly, member is not part of the prototype.

That's why you need to cast it, as my original answer says.


2nd edit

Here's something that works and might be what you're after:

type EntityStatic = {
    new (...args: any[]): Entity;
    member: string[];
}

function Decorator(constructor: EntityStatic) {
    ...
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download