Repository: TypeScript
Issue: Request: keyword or operator for iterating unions
Labels: Suggestion,Awaiting More Feedback

# 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.

```typescript
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.

```typescript
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

<!--
  💡 Did you know? TypeScript has over 2,000 open suggestions!
  🔎 Please search thoroughly before logging new feature requests as most common ideas already have a proposal in progress.
  The "Common Feature Requests" section of the FAQ lists many popular requests: https://github.com/Microsoft/TypeScript/wiki/FAQ#common-feature-requests

  Replace the text below:
-->

Iterating unions, distributing unions, T extends T ? T : never

## ✅ Viability Checklist

<!--
   Suggestions that don't meet all these criteria are very, very unlikely to be accepted.
   We always recommend reviewing the TypeScript design goals before investing time writing
   a proposal for ideas outside the scope of the project.
-->
My suggestion meets these guidelines:

* [X] This wouldn't be a breaking change in existing TypeScript/JavaScript code
* [X] This wouldn't change the runtime behavior of existing JavaScript code
* [X] This could be implemented without emitting different JS based on the types of the expressions
* [X] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
* [X] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).


## ⭐ Suggestion

<!-- A summary of what you'd like to see added or changed -->

Add a keyword that explicitly iterates types in a union instead of relying on conditional types.

```typescript
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

<!--
  If you were announcing this feature in a blog post, what's a short explanation that shows
  a developer why this feature improves the language?
-->

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 on `T`. 

The resulting type is a union of all keys in `T` whose members are type `F`.

Example
```typescript
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
```typescript
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:
```typescript
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.

 ```typescript
 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

<!--
  What do you want to use this for?
  What shortcomings exist with current approaches?
  What workarounds are you using in the meantime?
-->
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.