The inline function is meant to be used only by hof
, so TS can infer it's type safely.
But when the function is defined elsewhere and it's reference is passed to hof
, TS cannot assume that the function is only meant to be used by hof
because it can be used in other places as well. The only thing TS wants now is that the function that is being passed to hof
is type compatible with what hof
expects, in other words the type of the function being passed should be compatible with type: (a: string) => string
.
And this becomes more clear when you observe the complaint by TS, the complaint is not at all related to hof
, even if you remove all the other code and just have the someFunc
function definition, TS would still be complaining, so there's no association between someFunc
and hof
and TS is simply complaining because of the implicit any
type that the parameter a
gets (refer to the --noImplicitAny
compiler option).
If you explicitly state that argument a
could be of type any
, then there would be no complaints because (a: any) ⇒ string
is compatible with (a: string) => string
.
Finally, let's consider the following example:
function hof1(cb: (a: string) => string): void {}
function hof2(cb: (a: number) => string): void {}
function someFunc(a: string | number): string {
return `${a}`;
}
hof1((a) => a.toUpperCase());
hof2((a) => a.toFixed(2));
hof1(someFunc);
hof2(someFunc);
In the example someFunc
is being used for both hof1
and hof2
, so it makes it more clear why TS wasn't able to make any assumption, because someFunc
is more generic as compared to what either hof1
or hof2
accepts. But with that inline function TS knew that it's exactly what hof
accepts because that's the only place it can be used.