- 
                Notifications
    You must be signed in to change notification settings 
- Fork 13.1k
Description
Suggestion
π Search Terms
contextually context-sensitive generic inference unused parameter method object literal
β 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
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
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 => 0should not be contextually sensitive because the relational target(n: number) => Tdoes not useTin 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, orundefined). 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.