Update Feb 20, 2018: posted this as an issue on GitHub.
Update Feb 28: closed that issue in favor of a new one.
In the following code snippet, if you look at the last two lines, TypeScript shows an error in the first one, and correctly infers types in the second one, although the difference is only the order in which the functions are piped.
const pipe = <A, B, C>(
x: A,
a: (x: A) => B,
b: (x: B) => C,
) => b(a(x));
// This just calls the function passed as argument.
const call = <A, B>(f: (x: A) => B) => (x: A) => f(x)
const a = pipe(1, x => x + 1, call(x => x + 1));
const b = pipe(1, call(x => x + 1), x => x + 1);
I use TypeScript 2.7.1 in the strict mode (including strictFunctionTypes), however the strict mode doesn't seem to matter here. Here is this snippet on TypeScript playground.
It is a problem that I often run into when working with RxJS, since in RxJS there is a similar pipe
method and I pass arrow functions to it when using creation operators (like obs => merge(obs, otherObs)
). Usually it's easy to work around this problem by specifying the argument type, but I would like to understand the logic behind this. Why is TypeScript able to infer the type in one case but not in the other?
TypeScript infers types of variables when there is no explicit information available in the form of type annotations. Types are inferred by TypeScript compiler when: Variables are initialized. Default values are set for parameters.
Types of Functions in TypeScript: There are two types of functions in TypeScript: Named Function. Anonymous Function.
contextual typing in typescript is a form of type checking Archives | Agira Technologies.
The best common type algorithm In this case, TypeScript selects the number array type ( number[] ) as the best common type. In this example, TypeScript infers the type for arr to be (RegExp | Date)[] .
This issue is still outstanding, but for now I wanted to post a workaround that I've come up with because I found it very useful in my experience.
Create a utility function like this:
export const call = <A, B>(f: (x: A) => B) => f;
(the same function as in the question, an identity function that takes a unary function as argument), and then whenever you run into trouble with an arrow function in your pipe, try enclosing it with this utility function. Counterintuitively, TS can't handle this:
const a = pipe(1, x => x + 1, call(x => x + 1));
but it can handle this:
const c = pipe(1, call(x => x + 1), call(x => x + 1));
(no idea why). Later when the issue is fixed (go ahead an upvote it: https://github.com/Microsoft/TypeScript/issues/22081), you'll be able to easily find all references to call
and remove them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With