Description
In fixing a problem with the typings for the RxJS first
and last
operators, 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
interface Foo<T> {}
interface Bar<T, S> {}
export function foo<T, S extends T>(predicate: (value: T) => value is S, defaultValue?: S): Bar<T, S>;
export function foo<T>(predicate: (value: T) => boolean, defaultValue?: T): Foo<T>;
export function foo<T>(predicate: (value: T) => boolean, defaultValue?: any): Bar<T, any> | Foo<T> {
throw new Error('Unimplemented');
}
For the behaviour to be effected, strictFunctionTypes
must be true
and strictNullChecks
must be false
:
{
"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:
const predicated = foo(x => x === 's', 's'); // Foo<"s">
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:
const predicated = foo(x => x === 's', 's'); // Foo<string>
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 a string
source, as string
won'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 strictNullChecks
option?
Related Issues: None found.