In TypeScript, if a function expression is passed as an argument, the types of its parameters are inferred perfectly:

var foo = (fn: (a: string) => void) => {};

foo(a => {
// a is inferred to be a string
alert(a.toLowerCase());
});

It's really convenient for event handlers and other callbacks. However, if the function expression is wrapped in a call of a generic wrapper function, which takes a function as a parameter and returns a function with the same signature (except for return value), e.g.

Firstly, when you call a generic function without type arguments, the compiler has to figure out the type for each type parameter.

So when you call debounce, the compiler has to find candidates for the type of T. But the only place debounce can draw inferences from is your function, and you didn't give an explicit type for your type parameter.

So the compiler figures it doesn't have any types to work with, and falls back to {} (the "empty type", often just called "curly curly") for T.

That whole process is called type argument inference.

What then happens is that the compiler will notice that you haven't given your arrow function's parameters a type. Rather than defaulting to any, it figures that it can figure it out from the type of debounce's parameters. This process is called contextual typing.

Well fn's type is basically (a: {}) => void, so the compiler figures "alright, great, we can give a a type!" which ends up being... {} unfortunately.

So while this isn't totally absolutely awesome, the fix isn't really that bad. Just add a type annotation for a: