Skip to content

Function.prototype.bind typings do not work properly when supplied a function with variadic arguments. #42196

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
benlesh opened this issue Jan 3, 2021 · 2 comments
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@benlesh
Copy link

benlesh commented Jan 3, 2021

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

image

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.

@benlesh benlesh changed the title Function.prototype.bind typings are do not work properly when supplied a function with variadic arguments. Function.prototype.bind typings do not work properly when supplied a function with variadic arguments. Jan 3, 2021
@benlesh
Copy link
Author

benlesh commented Jan 3, 2021

Additionally, for a "real world" example of where this doesn't work properly. You can use readdir from Node.js:

const readHome = readdir.bind(null, '~/home');

readHome((err, results) => {
    if (err) {
        throw err;
    }
    for (const result of results) {
        console.log(result);
    }
});

Playground link here

@RyanCavanaugh RyanCavanaugh added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Jan 6, 2021
@RyanCavanaugh
Copy link
Member

See #38353

strictBindCallApply / typed bind work by picking up the argument list and trafficking it through to the output function type; this process isn't able to handle multiple overloads.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

2 participants