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

Allow arbitrary expressions in 'extends' clauses #511

Closed
RyanCavanaugh opened this issue Aug 22, 2014 · 0 comments
Closed

Allow arbitrary expressions in 'extends' clauses #511

RyanCavanaugh opened this issue Aug 22, 2014 · 0 comments
Labels
ES6 Relates to the ES6 Spec Fixed A PR has been merged for this issue Suggestion An idea for TypeScript

Comments

@RyanCavanaugh
Copy link
Member

The language currently only allows dotted identifiers in extends clauses, e.g. class Foo extends X.Y.Bar { }. The identifier must resolve to a class in both the value and type namespaces.

With the advent of class expressions (#497), we'll presumably need to start allowing arbitrary expressions, or at least loosen up the restriction that the named parent be an actual class.

var B: /* ... */;
class A extends B { }

The question is, given the type of B, how do we determine the type of A? Any rule should ideally end up at the same result as the current type system when B is a class.

Construct signatures?

Rule
The simplest rule would be that the return type of the construct signature of B is the prototypal parent of A. The constructor of A must invoke that construct signature (via super) according to the same rules as usual.

Issues
Problematically, B can actually have any number of construct signatures, with no restriction:

interface Evil {
  new(n: string): Horse;
  new(n: number): Airplane;
}
var B: Evil;
// What is A??
class A extends B { }

We cannot use A's super call to resolve the ambiguity via overload resolution because A might be an ambient class, in which case we won't know which super overload was selected.

Prototype?

Rule
TypeScript defines the prototype property of a class constructor function to be the same as the instance shape of the class. This is the prototypal parent of A, and A's constructor must call one of B's construct signatures via super.

Issues
The prototype property replaces all references to A's type parameters with any, erasing the genericness of the type.

Decision points

Questions to consider at this point:

  • Do base class expressions really need to have a prototype property? Probably not.
  • Are types with random construct signatures realistic base types? Probably not.

Compromise

Rule
A class extending some type B has a prototypal parent of the best common type of the return types of B's construct signatures. This best common type must exist (not {}), and all of B's construct signatures must have same number of generic type parameters. The extending class must specify that same number of generic type arguments when referencing B in the extends clause, which are then applied to the BCT of B's construct signature. Otherwise, it is an error to attempt to extend from B.

If a super call is required, the extending type's constructor may invoke any construct signature of the base type.

TBD

  • How does static inheritance work here?
@mhegazy mhegazy added this to the TypeScript 1.6 milestone Jun 18, 2015
@mhegazy mhegazy added Fixed A PR has been merged for this issue and removed Needs More Info The issue still hasn't been fully clarified labels Jun 18, 2015
@microsoft microsoft locked and limited conversation to collaborators Jun 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
ES6 Relates to the ES6 Spec Fixed A PR has been merged for this issue Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

2 participants