Repository: TypeScript
Issue: Feature request: typed yield expression
Labels: Suggestion,Awaiting More Feedback

<!-- 🚨 STOP 🚨 𝗦𝗧𝗢𝗣 🚨 𝑺𝑻𝑶𝑷 🚨

Half of all issues filed here are duplicates, answered in the FAQ, or not appropriate for the bug tracker.

Please help us by doing the following steps before logging an issue:
  * Search: https://github.com/Microsoft/TypeScript/search?type=Issues
  * Read the FAQ, especially the "Common Feature Requests" section: https://github.com/Microsoft/TypeScript/wiki/FAQ

-->
## Search Terms
generator, iterator, yield, type inference, co, redux-saga
<!-- List of keywords you searched for before creating this issue. Write them down here so that others can find this suggestion more easily -->

## Related Issues
#32523

## Suggestion

<!-- A summary of what you'd like to see added or changed -->
Allow passing of yield operator signature to generator functions
```typescript
declare function fetchUser(): Promise<User>;
function asyncAction*(yield: <R>(p: Promise<R>) => R) {
  const user = yield fetchUser(); // user type inferred to User based on yield param
  // impl
}
```
where `yield` inside params list is a pseudo-parameter similar to `this`.

## Use Cases

<!--
What do you want to use this for?
What shortcomings exist with current approaches?
-->
Discussion of use cases is given in #32523.

My intended use is case is emulating do notation for monads with generator functions.
This implies I would normally have some generator runner that does composition defined before writing generator function, so type of expression at which generator resumes is trivially inferrable based on yielded value.

## Discussion

<!-- Show how this would be used and what the behavior would be -->
The hard thing in typing `yield` expressions in is that resumed type does not depend only on passed parameters and generator type, but also on context in which the generator is run.

There is a precedent in TypeScript with similar situation -- `this` parameter in functions.
The situation is analogous -- what `this` behaves like depends on which object function is member of.

The proposal is to allow declaring contextual info about `yield` inside generator functions, by introducing appropriate pseudo-param.

I could see this working in two ways:
- `yield` param gets erased early, it does not affect generator function signature,
it serves merely as a contract for type-checking / inferrence inside body
```typescript
function asyncAction*(yield: <R>(p: Promise<R>) => R) {
  // impl
}
typeof asyncAction == () => Generator<...>
```
- `yield` param is preserved as type info like `this` param. 
then it is always present on types of shape `(yield: ...) => Generator<>` and defaults to `(a: any) => any`.
```typescript
function asyncAction*(yield: <R>(p: Promise<R>) => R) {
  // impl
}
typeof asyncAction == (yield: <R>(p: Promise<R>) => R) => Generator<...>
```

Additionaly
1. signature of `yield` must extend `(a: any) => any` and defaults to it
```typescript
function asyncAction*(yield: number) {
  // impl
}
// Error: signature must be of shape (any => any)
```
2. yielded values inside generator function body must be assignable to argument of `yield` signature
```typescript
function asyncAction*(yield: (s: string) => void) {
  yield 7; // Error: number is not assignable to string
}
```
3. this parameter has no effect on `Generator<>` return type, whether declared or 
  other than obvious coherence guaranteed by (2)

## Checklist

My suggestion meets these guidelines:

* [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
  thats an opt-in feature
* [x] This wouldn't change the runtime behavior of existing JavaScript code
  type level feature, doesn't affect runtime behavior
* [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, etc.)
* [x] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).