Repository: TypeScript
Issue: Improve inference in the presence of context-sensitive expressions
Labels: Suggestion,Help Wanted,Experimentation Needed

# Suggestion

<!--
  Please fill in each section completely. Thank you!
-->

## 🔍 Search Terms

contextually context-sensitive generic inference unused parameter method object literal

## ✅ Viability Checklist

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

When generic inference is gathering candidates, context-sensitive expressions should still be considered if it's possible to do so without observing a type parameter from the call.

## 📃 Motivating Example

```ts
declare function callIt<T>(obj: {
    produce: (n: number) => T,
    consume: (x: T) => void
}): void;

// Works
callIt({
    produce: () => 0,
    consume: n => n.toFixed()
});

// Fails for no obvious reason
callIt({
    produce: _a => 0,
    consume: n => n.toFixed()
});

// Fails for no obvious reason
callIt({
    produce() {
        return 0;
    },
    consume: n => n.toFixed()
});
```

## 💻 Use Cases

Background: expressions can be "context-sensitive" for the purposes of inference -- this is a syntactic property of an expression that tells us whether or not an expression's type *could* be dependent on the inference of its contextual type. For `_a => 0`, this is true because the return expression might depend on `_a` (including in indirect ways). For `produce() {`, it's context-sensitive because (unlike an arrow function) it takes its parent object type for `this`, so could depend on the type parameter via a reference of `this`.

When it turns out that the type of the expression is *not* actually dependent on the inference of the type parameter (which would represent a true circularity, thus more understandably non-working), then this just looks busted for no obvious reason. This is a continuous source of surprise and annoyance. (TODO: link user reports)

## Discussion

There are a few implementation strategies we could try, with varying trade-offs

 * Proceed to do structural inference on context-sensitive expressions but mark the type parameters symbols as "off limits" with logic to back out. This is likely impractically invasive
 * Perform a more robust check to determine "true" context-sensitivity -- for example, `produce: _a => 0` should not be contextually sensitive because the relational target `(n: number) => T` does not use `T` in a covariant position. There are multiple ways we could do this
 * Add an optional intermediate pass when inference collected no candidates when ignoring context-sensitive expressions where we go and collect from them anyway. This pass could safely fix parameters since they'd be going to `unknown`. This entire bullet point might be wrong.
 * As a stopgap, consider function expressions to not be context-sensitive if all of their return expressions can be trivially seen to not depend on earlier lines of code (e.g. are literals, literals of literals, `null`, or `undefined`). This might fix a surprisingly large class of reports
 * As a stopgap, consider an object literal method to not be context-sensitive if it doesn't reference `this`. I believe we already have code for this and it would fix another large class of surprises.