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

class constraints #9776

Closed
zpdDG4gta8XKpMCd opened this issue Jul 17, 2016 · 8 comments
Closed

class constraints #9776

zpdDG4gta8XKpMCd opened this issue Jul 17, 2016 · 8 comments
Labels
Duplicate An existing issue was already created

Comments

@zpdDG4gta8XKpMCd
Copy link

zpdDG4gta8XKpMCd commented Jul 17, 2016

I am looking for a way to get my derived class be inherited from a generic class.
This is my naive attempt to get it:

export function create<T>(base: { new (value: string): T }) {
  return new class extends base {
    constructor() {
      super('hey');
    }
  };
}

It might be that I am just doing it wrong, but looks like a current limitation, if so:

  • allow class expressions to be declared with a constructor function that returns a generic class

It might require a new syntax for class constraints:

export function create<class T>(base: { new (value: string): T }) {
  return new class extends base {
    constructor() {
      super('hey');
    }
  };
}
@jesseschalken
Copy link
Contributor

How would TS check that the anonymous class is compatible with base, when base is determined at run time?

Eg

class Foo {
    public fooMethod(x:number):string { return 'hello'; }
}

export function create<T>(base: { new(): T }) {
  return new class extends base {
      public fooMethod(x:string):void {}
  };
}

create<Foo>(Foo);

The anonymous class is overriding the fooMethod() with an incompatible signature, but there is nothing in the signature of create() that should prohibit Foo from filling T. You would need to somehow express in the signature of create() that T must either not have a fooMethod or has a fooMethod with a signature that (x:string):void is compatible with (i.e. the override will be compatible).

@zpdDG4gta8XKpMCd
Copy link
Author

A good question, it is certainly possible:

  • at the time of calling create when the type parameter T gets resolved to a real type
  • or declaratively in the signature of create by constraining T unlike C where C is the type of the anmonitors class: negating type constraints #7993

@Artazor
Copy link
Contributor

Artazor commented Jul 17, 2016

Seems that @ahejlsberg already shown some workaround for the problem described by @Aleksey-Bykov, could not find, though.

@Aleksey-Bykov, I completely agree that we need something like that. However @jesseschalken is also right. I'd propose other solution, that can look way to far from your solution (class constraint) but will help to solve the same problem.

I would propose the special type constructor: T overrides U
It is not a constraint, it is a type. So you freely can write:

var a: {x: number} overrides {x: {}, y: boolean}; 
    // and get the correct { x: number, y: boolean}

As well as

var X: TExtension overrides TBase; 
  // where both TExtension and TBase are generic type params

This operator ensures that extension is correct at the instantiation time.

var a: {x: number} overrides {x: string, y: boolean}; 
   // error:  number and string are not compatible   

Guys, what do you think?

@Artazor
Copy link
Contributor

Artazor commented Jul 17, 2016

in my case, @jesseschalken example would look like:

export function create<T>(base: new() => T }): {
  fooMethod(x: string): void
} overrides T {
  return new class extends base {
      public fooMethod(x:string):void {}
  };
}

class Foo {
    public fooMethod(x:number):string { return 'hello'; }
}

create<Foo>(Foo); // error at compile time

@Artazor
Copy link
Contributor

Artazor commented Jul 17, 2016

For all actual types T and U the type T overrides U inferred exactly according to the TypeScript member overriding rules.

ping @RyanCavanaugh

@zpdDG4gta8XKpMCd
Copy link
Author

I like overrides

@mhegazy
Copy link
Contributor

mhegazy commented Jul 17, 2016

looks like a duplicate of #4890

@mhegazy mhegazy added the Duplicate An existing issue was already created label Jul 17, 2016
@Artazor
Copy link
Contributor

Artazor commented Jul 17, 2016

@mhegazy - exactly, it's that duplicate I've tried to find. @Aleksey-Bykov let's go there and move the process forward -)

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants