microsoft / microsoft/TypeScript

[Feature Request] Non-Union Generic Type Params

Offen
#32,909 14 Kommentare 1 Reaktion 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Awaiting More Feedback Suggestion
Vorherrschende Sprache
Go
Sterne
111k
Forks
14.3k
Ø Merge
1 T. 19 Std.
Gemergte PRs (30 T.)
117

Beschreibung

Search Terms

  • non-union
  • generic
  • type param
  • one of

Suggestion

A way to annotate that a generic type param will not accept union types.
I don't have the syntax or keyword in mind, but I'll just go ahead and use nonUnion as a kind of type param modifier,

type NonUnionX<nonUnion T> = (
  /*Implementation*/
);

Use Cases

What do you want to use this for?

I work with pretty complex types (in my opinion); and a lot of them.

When working on a complex type, I tend to break the problem down into smaller subproblems.

The base case is usually assuming that all type params are non-union.
After that, I build on top of the base case and implement types that support union type params.


Here is an example type that is a base case,
PrimaryKey_NonUnion<TableT>


And here is an example of a type building upon the base case,
PrimaryKey_Output<TableT>

It distributes TableT and uses PrimaryKey_NonUnion. The result is a union if TableT is a union.


And here is an example of another type building upon the base case,
PrimaryKey_Input<TableT>

It distributes TableT and uses PrimaryKey_NonUnion.
Then, it uses UnionToIntersection<> to combine the results into one type.


That experimental repository of mine is filled with instances of generic types that support union types and those that do not.

There are times where you really do not want to pass a union type to a generic type param because it'll result in bugs that may not be noticed till later.

What shortcomings exist with current approaches?

One approach is to just write a comment that says,

/**
 * + Assumes `T` is not a union
 * + Assumes `U` may be a union
 * + Assumes `V` is not a union
 */

This gets very error-prone when you start having hundreds of types.


Another approach is to give your types names that are descriptive,

type SomeOperation_NonUnionT_UnionU_NonUnionV<
  T,
  U,
  V
> = (
  //Implementation
);

This is still error-prone; you may still use it incorrectly.
Even if the name of the type says NonUnionT, you may still pass a union type to T.

Examples

type NonUnionX<nonUnion T> = (
  /*Implementation*/
);
//OK
type nonUnionX1 = NonUnionX<string>;
//Error, Type `NonUnionX` expects non-union for type parameter `0`
//  `string|number` is a union type
type nonUnionX2 = NonUnionX<string|number>;
//                          ~~~~~~~~~~~~~

type UnionX<T> = (
  T extends any ?
  //OK! `T` has been distributed
  NonUnionX<T> : 
  never
);
//OK
type unionX1 = UnionX<string>;
//OK
type unionX2 = UnionX<string|number>;

type Blah<T> = (
  //Error, Type `NonUnionX` expects non-union for type parameter `0`
  //  `T` may be a union type
  NonUnionX<T>
  //        ~
);

A non-approach is to expose only types that handle union type params and to leave non-union implementations unexported.

This is not a useful approach because it means building new types in a different file using these non-union implementations becomes impossible. Since they're unexported.

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, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

Similar issues

https://github.com/microsoft/TypeScript/issues/24085
https://github.com/microsoft/TypeScript/issues/27808

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne mit der Durchsicht der vorgeschlagenen Beispiele und der zugehörigen Issues 24085 und 27808 und untersuche anschließend die referenzierten tsql-Beispiele in src/primary-key/primary-key.ts. Erledigt ist die Aufgabe, wenn generische Parameter Union-Typen ablehnen können und gleichzeitig das gezeigte distributive Muster weiterhin zulassen; Syntax und Compilerdesign bleiben nicht spezifiziert.

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
25/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.