Repository navigation
Type inference regression with overloads #27972
Description
Activity
This is working as intended. First, some clarifications. This is a change introduced in 3.1, not a new change in 3.2 as implied above, and the issue surfaces only in
--strictFunctionTypesmode.The change in 3.1 is that when, in
--strictFunctionTypesmode, we have both co- and contra-variant inferences for a type parameter, we prefer the contra-variant inference unless the co-variant inference is a subtype and notnever. That causes us to infernumberinstead ofvoidin the example (which, for those two candidates, is the correct choice).Now, the real issue is that we only make inferences from the last overload because we're inferring from a type with two signatures to a type with only one signature. We've always had the rule that we match signatures pair-wise from the bottom when doing inference, so nothing new there. However, it means that nothing is or was ever inferred from the first overload, and it just so happened to work previously because we made a bad inference from the second overload.
- addedWorking as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bugand removedBugA bug in TypeScriptA bug in TypeScript
on Nov 4, 2018 Hi,
I think I have a related bug that is failing due to this issue:
export interface DocumentType<T> { hasKey(key: keyof T): boolean; } export interface DocumentTypeConstructor { new<T>(value: T): DocumentType<T>; } export const DocumentType: DocumentTypeConstructor = class <T> { private readonly value: T; constructor(value: T) { this.value = value; } hasKey(key: keyof T): boolean { return key in this.value; } };
I get
error TS2394: Overload signature is not compatible with function implementation.associated tohasKeyin the first interface (see playground).
This code was compiling in3.0but started to fail in3.1.I found that the following code fixes the issue, but I don't understand why:
export interface DocumentType<T> { hasKey(key: keyof T): boolean; } export interface DocumentTypeConstructor { new<T>(value: T): DocumentType<T>; } export const DocumentType: DocumentTypeConstructor = class <T> { private readonly value: T; constructor(value: T) { this.value = value; } hasKey<TT extends keyof T>(key: TT): boolean { return key in this.value; } };
The only difference is that I modified the signature of the implementation from
hasKey(key: keyof T): booleantohasKey<TT extends keyof T>(key: TT): booleanbut in my opinion both should be equivalent. What am I missing?typescript-bot commented
on Dec 13, 2018 ContributorMore actionsThis issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.
- locked as resolved and limited conversation to collaborators
on Oct 21, 2025
TypeScript Version: 3.2.0-dev.20181018
Search Terms:
Code
Expected behavior:
No error, as in
typescript@3.1.Actual behavior:
Looks like this was introduced by #27028. Discovered in
bluebirdon DefinitelyTyped -- in that case it had to do withtype CatchFilter<E> = (new (...args: any[]) => E) | ((error: E) => boolean) | (object & E);which unions a construct and call signature which more clearly should be separate.