Closed
Description
Bug Report
If you pass a function that might behave differently when supplied different arguments, the resulting type does not properly accommodate all call patterns.
I ran into this while trying to figure out how TypeScript handled situations similar to RxJS's bindNodeCallback
and bindCallback
, which suffers from similar problems.
🔎 Search Terms
bind
bind "Arguments for the rest parameter"
🕗 Version & Regression Information
versions 3.3.* - 4.1.3
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about (I have no idea where the FAQ is, reporting anyway, because this is friction)
⏯ Playground Link
Playground link with relevant code
💻 Code
interface A {
a: string;
}
interface B {
b: string;
}
interface C {
c: string;
}
interface D {
d: string;
}
const a: A = { a: 'a' };
const b: B = { b: 'b' };
const c: C = { c: 'c' };
const d: D = { d: 'd' };
// Let's say these are the only valid ways to
// call our `test` function:
function test(a: A, b: B): A; // 1
function test(a: A, c: C): B; // 2
function test(a: A, b: B, d: D): C; // 3
// "impl" here
function test(a: A, bOrC: B | C, d?: D): A | B | C {
if (isA(a)) {
if (isB(bOrC)) {
if (isD(d)) {
return { c: 'test' }; // 3
} else {
return { a: 'test' }; // 1
}
}
if (isC(bOrC)) {
return { b: 'test' }; // 2
}
}
throw new Error('wrong call');
}
function isA(input: any): input is A {
return input && 'a' in input && typeof input['a'] === 'string';
}
function isB(input: any): input is B {
return input && 'b' in input && typeof input['b'] === 'string';
}
function isC(input: any): input is C {
return input && 'c' in input && typeof input['c'] === 'string';
}
function isD(input: any): input is D {
return input && 'd' in input && typeof input['d'] === 'string';
}
const x = test.bind(null, a, b);
const r = x();
console.log(r);
🙁 Actual behavior
I got a compilation error for a perfectly valid call of my bound function.
🙂 Expected behavior
The return type (the type of r
) should be C
, and the code should compile successfully.