Repository navigation
Unrelated overload signature affects inference #25917
Description
Activity
- addedDesign LimitationConstraints of the existing architecture prevent this from being fixedConstraints of the existing architecture prevent this from being fixedand removedBugA bug in TypeScriptA bug in TypeScript
on Jul 25, 2018 This is a design limitation of how overload resolution is implemented. when the compiler is trying to resolve overloads it goes through them in order one at a time trying to see which is a fit. The arguments to the function can be "contextually sensitive", i.e. their type depends on the containing context, for instance function expressions or object literals. in this case the compiler will try to infer a contextual type to go with the function expression. the type is then used to contextually type the function expression, and then check the body of the function to infer the return type. if that fits, then good, the signature is picked, if that does not the compiler moves on to the next overload. the issue here is once a function expression gets a contextual type, there is no going back. the compiler can not just remove the type and recheck it (that is not how it is implemented). so what happens is that the next overload will have the same contextual type from the previous overload, (
{}in the OP). So though the first overload was not picked, it did contribute to the type of your function expression.A better implementation of overload resolution would be one that can erase contextual types, and try others without side effects. this, however, is a tantamount to a complete rewrite to the overload resolution logic, and has some drastic impacts on performance.
Andy (Andrewkraft) (@Andy-MS) The behaviour is sensitive to the compiler options mentioned in the issue:
"strictFunctionTypes": true, "strictNullChecks": false
For example, if
strictNullChecksistrue, the inferred type will beFoo<{}>.Mohamed Hegazy (@mhegazy) Why is the behaviour different - with
Foo<{}>inferred instead ofFoo<"s">- if the seemingly unrelatedstrictNullCheckscompiler option istrueinstead offalse?I am not seeing that on the latest version of the compiler.
Apologies. I thought that VS Code used the local version of TypeScript - as that's what the linting extension does. I can see now that I was wrong. (In fact, the TS version used by VS Code is indicated in the toolbar.)
I created a small compiler API harness and the behaviour's dependency on the compiler-options appears to have been addressed in version 3.0, as the
3.0.0-rcrelease infersFoo<{}>regardless of the compiler options.
In fixing a problem with the typings for the RxJS
firstandlastoperators, I've stumbled across some weird behaviour with overload signatures.TypeScript Version:
next(3.1.0-dev.20180725)Search Terms:
overload signature inference unrelated incorrect
Code
For the behaviour to be effected,
strictFunctionTypesmust betrueandstrictNullChecksmust befalse:{ "compilerOptions": { "strictFunctionTypes": true, "strictNullChecks": false }, "files": ["index.ts"] }Expected behavior:
When passing a function that is not a user-defined type guard, I'd expect the inferred type to be independent of whether or not the type-guard-accepting overload signature is available or is commented out.
Actual behavior:
However, if the signature that accepts a type guard is available, the inferred type - for a call that does not involve a user-defined type guard - will be:
And if the signature that accepts a type guard is commented out, the inferred type - for a call that does not involve a user-defined type guard - will be:
In RxJS, this causes a problem when the operators are used with
pipe. If a return type with a string literal is inferred - e.g.MonoTypeOperatorFunction<"s">- an error will be effected if the operators are used with astringsource, asstringwon't be assignable to"s".Also, why is the behaviour dependent upon the above-mentioned compiler options? In particular, why does it depend upon the
strictNullChecksoption?Related Issues: None found.