microsoft / microsoft/TypeScript
Request: keyword or operator for iterating unions
Nessuno ha ancora preso questa issue.
- Lingua principale
- Go
- Stelle
- 111k
- Fork
- 14.3k
- Merge medio
- 2g 4h
- PR unite (30g)
- 132
Descrizione
Suggestion
I'm sorry, I feel like this has definitely been suggested but I couldn't find it in issues.
I think there should be a more explicit way to force iterating through types of a union in generics than what we currently have. The easiest example I can think of is the way keyof interacts with unions.
interface A {
foo: string;
}
interface B {
bar: number;
}
type C = A | B;
type Keys = keyof C; // never
I understand why it works this way. I'm not arguing that TypeScript is doing anything wrong. However, sometimes I want to get all the keys of all the members of a union, and the workaround is to abuse conditional types to force iteration.
type KeyofUnion<T> = T extends T ? keyof T : never;
type Keys = KeyofUnion<A | B>; // 'foo' | 'bar';
The expression T extends T ? /* something */ : never is silly enough that I feel it justifies creating a keyword. More importantly, it's not clear that types would behave this way if you didn't look it up. Why would conditional types force union iteration? I assume there is a good reason, but for someone not super familiar with TS, I would never expect them to see that and understand why anyone wrote it.
I believe this suggestion would be an improvement under #7 of the "non-goals" of the contributing guidelines.
🔍 Search Terms
Iterating unions, distributing unions, T extends T ? T : never
✅ 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.
⭐ Suggestion
Add a keyword that explicitly iterates types in a union instead of relying on conditional types.
type A {
foo: string;
}
type B {
bar: number;
}
type C = A | B;
type Keys = keyof in C;
type Keys = keyof union C;
type Keys = keyof memberof C;
I'm not happy with any of the ideas I have for the syntax but hopefully you can see what I'm going for.
📃 Motivating Example
I already put one example in the first section, but I'll also give a more concrete example of something I was trying to do that made me think of this.
I wanted to create a generic type that takes in two args.
T, an object- and
F, a type that exists as a member onT.
The resulting type is a union of all keys in T whose members are type F.
Example
interface Foo {
a: string;
b: number;
c: Date;
d: string;
e: string;
f: number;
}
type NumberKeys = KeysOfType<Foo, number>; // 'b' | 'f';
type StringKeys = KeysOfType<Foo, string>; // 'a' | 'd' | 'e';
type BoolKeys = KeysOfType<Foo, boolean>; // Error: Type 'boolean' does not satisfy the constraint 'string | number | Date'.
This was my first version of this type
type KeysOfType<T, F extends T[keyof T]> = {
[K in keyof T]: T[K] extends F ? K : never;
}[keyof T];
But, when I tried to pass a union in as the first argument, it didn't work the way I wanted it to. This led me to change it to this:
type KeysOfType<T, F extends T extends T ? T[keyof T] : never> = T extends T
? {
[K in keyof T]: T[K] extends F ? K : never;
}[keyof T]
: never;
This is much more cumbersome.
I'd love to see a way to force this without abusing conditional types.
type KeysOfType<T, F extends T[keyof in T]> = {
[K in keyof in T]: T[K] extends F ? K : never;
}[keyof T];
type KeysOfType<T, F extends T[keyof union T]> = {
[K in keyof union T]: T[K] extends F ? K : never;
}[keyof T];
Again, I really don't have any good ideas for the syntax, but hopefully the spirit of this request is clear at this point.
💻 Use Cases
I'm having a hard time thinking of another use case than the one I provided here, so maybe it's edge enough to be too low priority. I still think it'd be nice to have an explicit way to do this.
Thanks for reading this and have a good day.
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Inizia esaminando il workaround basato sui tipi condizionali dell’issue, il comportamento di keyof sulle unioni e gli obiettivi di progettazione di TypeScript collegati. Confronta le idee di sintassi proposte in, union e memberof con gli esempi motivanti. Per considerare il lavoro completato, è necessario concordare un design del linguaggio e l’ambito dell’implementazione, che questa issue non specifica ancora.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- typescript
- Ambito
- compilers
- Tipo di issue
- Funzionalità
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Stato di attività
- Ferma
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 25/100