Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't access to static member of generic class from a decorator. #17454

Closed
lilezek opened this issue Jul 27, 2017 · 6 comments
Closed

Can't access to static member of generic class from a decorator. #17454

lilezek opened this issue Jul 27, 2017 · 6 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@lilezek
Copy link

lilezek commented Jul 27, 2017

Stack overflow url of this issue: https://stackoverflow.com/questions/45347630/accessing-static-member-of-generic-class-from-a-decorator

TypeScript Version: nightly (2.5.0-dev.20170725)

Code

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

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

Expected behavior:

I would expect to be able to access the static member from the Decorator.

Actual behavior:

Member is not part of type T.

@ghost
Copy link

ghost commented Jul 27, 2017

You can't access that property because you never declared it in the type bound for T. You would have to declare T extends { member: string[]; new(...args: any[]): Entity; }.

@DanielRosenwasser DanielRosenwasser added the Question An issue which isn't directly actionable in code label Jul 27, 2017
@lilezek
Copy link
Author

lilezek commented Jul 28, 2017

Well, as this is labeled as question, I'm going to make a question about what I want to achieve.

Is it possible to have a generic type T extended from Entity, where I can access static elements from Entity without explicitly have to write twice the Entity's structure or doing any casting?

People are suggesting things at https://stackoverflow.com/questions/45347630/accessing-static-member-of-generic-class-from-a-decorator but all suggestions are casting or writing twice the structure.

@lilezek
Copy link
Author

lilezek commented Jul 28, 2017

Another example of what I think that it shouldn't be mandatory to do:

function decorator<T extends typeof Entity>(C: T) {
  return class extends (C as typeof Entity) { // Why is this cast necessary?
    constructor(...args: {}[]) {
      super(...args);
      C.member.forEach((v) => {
        // ...
      });
    }
    x = 1;
    y = 2;
    static z = 3;
  } as {} as T; 
}

This code is from StackOverflow example, where a cast from C to typeof Entity seems mandatory in order to the compiler to work. Isn't C, which is of type T, which is an extension of typeof Entity, enough to be extended as a new anonymous class?

@ghost
Copy link

ghost commented Jul 29, 2017

If your decorator is only going to apply to exactly one class, you could just use C: typeof Entity.
If you're using the decorator on many different classes, wouldn't it make sense to declare an interface for what they should all have in common?
As for the cast, see #17504.

@aluanhaddad
Copy link
Contributor

aluanhaddad commented Jul 29, 2017

@lilezek thanks to @andy-ms's explanation, I realized I was mistaken in my answer in SO. To get this to work, Entitys constructor must have the signature new (...args: any[]) => any.

That is

class Entity {
  constructor(...args: any[]) {} // the ... is also required.
}

Any type that is used to refine the constraint also must contain the signature new (...args: any[]) => any. For example:

function decorator<T extends
  typeof Entity
  & {
    new(...args: any[]): any,
    prototype: {p: number}
  }
>(C: T) {
  return class extends C {};
}

will work but the following will fail

function decorator<T extends
  typeof Entity
  & {new(...args: any[]): any}
  & {prototype: {p: number}}
>(C: T) {
  return class extends C {};
}

@mhegazy
Copy link
Contributor

mhegazy commented Aug 17, 2017

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@mhegazy mhegazy closed this as completed Aug 17, 2017
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

4 participants