Search code examples
javascripttypescriptlodash

Lodash using curry with bind cause a typescript error


I'm trying to use the bind method with curry, but it gives me a type error.

const curried = curry(this.method.bind(this));
const getSomething = curried(a, b);

Getting TS error from getSomething:

expected 0-1 arguments but got 2.

When I am not using the bind method it's not complaining.

const curried = curry(this.method);
const getSomething = curried(a, b);

Solution

  • The problem is that this is the signature of bind:

    bind(this: Function, thisArg: any, ...argArray: any[]): any;
    

    So the return of bind for a function is any, curry still works because any can be converted to any other type, so the first overload in declaration order of curry is used namely this one:

    curry<T1, R>(func: (t1: T1) => R, arity?: number): CurriedFunction1<T1, R>;
    

    With T1 and R being inferred to {}.

    This is a reason to stay away from bind, it loses type info. It is difficult to write a general type safe version of bind, since it can bind both this and function arguments, but a version that just binds this and preserves type info in easy to write:

    function typedThisBind<T1, T2, T3, T4, R>(fn: (t: T1, t2: T2, t3: T3, t4 : T4) => R, thisArg: any) : typeof fn
    function typedThisBind<T1, T2, T3, R>(fn: (t: T1, t2: T2, t3: T3) => R, thisArg: any) : typeof fn
    function typedThisBind<T1, T2, R>(fn: (t: T1, t2: T2) => R, thisArg: any) : typeof fn
    function typedThisBind<T1, R>(fn: (t: T1) => R, thisArg: any) : typeof fn
    function typedThisBind<R>(fn: () => R, thisArg: any) : () => R
    function typedThisBind(fn: Function, thisArg: any) : any {
        return fn.bind(thisArg);
    }
    

    Now using this version of bind all should work as expected (for functions with up to 5 arguments, but you can easily add more):

    class Foo {
        method(a: number, b: number) {}
        m(){
            const curried = curry(typedThisBind(this.method, this));
            const getSomething = curried(0, 0); // Works as expected.
        }
    }