Search code examples
typescriptdefinitelytyped

Typescript error when curried defition is after the uncurried definition


I am receiving error: Expected 1 arguments, but got 2.ts(2554) when I place uncurried definition of method above the curried definition.

Failing dtslint test:

function match(regExpression: RegExp, str: string): string[]; 
function match(regExpression: RegExp): (str: string) => string[]; 

function throttle<T, U>(fn: (input: T) => U, ms: number): (input: T) => U;
function throttle<T, Q, U>(
  fn: (input1: T, input2: Q) => U, ms: number
): (input1: T, input2: Q) => U;

it('match', () => {
    const fn = throttle(match, 1000)
    fn(/foo/,'foo bar')  // line of error
})

If I move the curried match definition above the uncurried definition, then the error disappears.

My question is should I indeed place uncurried version after the curried version, or there is error in throttle definition?


The context of the question is writing Typescript definitions for a library similar to ramda.


Solution

  • Typescript checks overloaded signatures (which are internally intersection types) in top to bottom order. When throttle chooses which signature to use to infer generic parameters (almost same as conditional types), it always selects last signature.

    Closely related feature of TS type system is described here:

    When inferring from a type with multiple call signatures (such as the type of an overloaded function), inferences are made from the last signature (which, presumably, is the most permissive catch-all case). It is not possible to perform overload resolution based on a list of argument types (this would require us to support typeof for arbitrary expressions, as suggested in #6606, or something similar).