microsoft / microsoft/TypeScript
Allow overloading constructors with type parameters to instantiate the same class but with different generics
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Go
- Sterne
- 111k
- Forks
- 14.4k
- Ø Merge
- 1 T. 19 Std.
- Gemergte PRs (30 T.)
- 117
Beschreibung
Suggestion
🔍 Search Terms
constructor overload return type parameter annotation generic
✅ Viability Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.
Previous Discussions & Related Issues
-
#10860
The closest to a duplicate of this proposal. Closed due to conflicts between generics on class and generics on constructor overloads. -
#11588
A feature request asking for TypeScript to allow setting any return type for a constructor. It was declined due to that pattern being considered bad practice. -
#27465
Quickly closed due to being a duplicate of the first issue, #10860, did not end up with much further discussion once it was closed, unfortunately. -
#27594
Asking again for TypeScript to allow setting the return type for a constructor. From what I can see, the issue does not specify whether the instance type should be assignable to the return type, or whether any return type should be allowed (IE, a straight rehash of #11588.) This issue is still open and has garnered a lot of discussion, but it's only tangentially related to this proposal.
⭐ Goals of this Proposal
1. Allow writing classes that generate the correct generics without requiring the consumer to provide any.
The ideal circumstances for class construction with generics is the following, where the consumer doesn't need to provide any type parameters:
// Ideal circumstances:
class Collection<T> {
constructor(iterable: Iterable<T>) {}
}
new Collection([1, 2, 3]) // Collection<number>
That, unfortunately, is not always possible. In the following example, for instance, the ideal return would use HTMLElementTagNameMap[TAG_NAME], but there's no way to do that:
class ElementWrapper<TELEMENT extends Element = Element> {
constructor(tagName: string) {}
}
new ElementWrapper("button") // ElementWrapper<Element>
new ElementWrapper<HTMLButtonElement>("button") // ElementWrapper<HTMLButtonElement>, but the consumer has to annotate it themself :(
2. Don't affect existing TypeScript code at all. Any new functionality should be layered over top what's already there.
When a developer isn't using any of the newly-allowed annotations, TypeScript should function exactly as it does now.
3. Don't introduce new syntax for providing type parameters to a constructor call.
4. Disallow constructors to be annotated as returning things not assignable to the class's type.
Returning anything is out of scope for this proposal.
🚀 Proposal
Constructor overload signatures can now have their own type parameters and provide a return type.
In order to allow this while still respecting the other stated goals above, this comes with the following restrictions:
-
When type parameters are specified, and the overload is called, the overload's type parameters are used instead of the class generics.
-
When a signature is using custom type parameters, it must, therefore, have a return type, otherwise there wouldn't be a way for TypeScript to determine the generics of new instances.
-
Any constructor return type must be assignable to the class's instance type. (As stated above, anything else is out of scope for this proposal.)
-
Again, only overloads may have type parameters or return types. The constructor implementation may not have type parameters or a return type, as it adds additional complexity to the proposal. The current errors will become
Type parameters can only appear on overloaded constructor declarations.andType annotations can only appear on overloaded constructor declarations.
Example
Using the above ElementWrapper example, we can now do the following:
class ElementWrapper<TELEMENT extends Element = Element> {
constructor<TTAG_NAME extends keyof HTMLElementTagNameMap>
(tagName: TTAG_NAME): ElementWrapper<HTMLElementTagNameMap[TTAG_NAME]>;
constructor(tagName: string) {}
}
Constructor overloads can use different type parameters from each other.
The functionality exactly mirrors function overloads, and allows for the following:
class ElementWrapper<TELEMENT extends Element = Element> {
constructor<TTAG_NAME extends keyof HTMLElementTagNameMap>
(tagName: TTAG_NAME): ElementWrapper<HTMLElementTagNameMap[TTAG_NAME]>;
constructor(tagName: string): ElementWrapper<Element>;
constructor(tagName: string) {}
}
Constructor overloads should not be handled any differently in TypeScript than they are now (yes, it already works!), using the complex newable interface syntax. (To note, while that syntax works for type definitions, if a bit awkwardly, trying to implement the class itself using those types is even more awkward.)
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Es werden keine Implementierungsdateien, Tests oder Compiler-Einstiegspunkte genannt. Beginne mit der Durchsicht des Vorschlags und der zugehörigen Issues #10860, #11588, #27465 und #27594; als abgeschlossen würde dies ein abgestimmtes Design und ein entsprechendes TypeScript-Verhalten erfordern, das generische Konstruktorüberladungen unterstützt, ohne bestehenden Code zu ändern.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- typescript
- Bereich
- compilers
- Issue-Typ
- Feature
- Schwierigkeit
- 5/5
- Geschätzter Aufwand
- Über eine Woche
- Aktivitätsstatus
- Veraltet
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 35/100