Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Polymorphic Anonymous Functions Type Aliases

It seems there's a subtle difference between type decleration for named function() syntax vs anonynous function syntax:

type F<X, Y> = (x: X) => Y

// works:
function apply<X, Y>(f: F<X, Y>, x: X) : Y {
    return f(x)
}

// works:
const apply0 : <X, Y>(f: F, x: X) => Y = (f, x) => f(x)

// doesn't work
const apply1 : <X, Y>(f: F<X, Y>, x: X) => Y = (f, x) => f(x)

Flow console snippet

I need to remove generic type annotation from any reference to type F<X, Y> in the arguments of anonymous apply function for type checker to work.

This is counterintuitive.

[Edit:] But it seems that Flow is able to type check apply1 calls even though it fails to type check apply1 itself:

apply1(x => x * 2, 'a') // error: ^ string. This type is incompatible with
apply1(x => x * 2, 1) // works

More generally:

// works:
type Apply<X, Y> = <X, Y>(f: F, x: X) => Y

const apply : Apply = (f, x) => f(x)    


// doesn't work:
type Apply1<X, Y> = <X, Y>(f: F<X, Y>, x: X) => Y

const apply1 : Apply1 = (f, x) => f(x)

Flow console snippet

I have to remove generic type annotation X, Y from the arguments of type alias Apply for Flow to type check it.

Is it the intended behavior or am I missing something?

like image 598
homam Avatar asked Dec 05 '25 06:12

homam


1 Answers

TL;DR: Try

const apply1 = <X, Y>(f: F<X, Y>, x: X): Y => f(x)

Explanation

First, as @squint mentioned in a comment, F without type arguments implicitly means F<any, any>, which is why apply0 works in your example.

So why does your apply1 have an error? Well, it's due to the fact that Flow does not infer generics. so when you wrote

const apply1 : <X, Y>(f: F<X, Y>, x: X) => Y = (f, x) => f(x)

the right hand side of the assignment is

(f, x) => f(x)

and Flow can't infer that this arrow function is polymorphic. So you could just add type parameters to the RHS like this:

const apply1 : <X, Y>(f: F<X, Y>, x: X) => Y = <X, Y>(f: F<X, Y>, x: X): Y => f(x)

and that should fix the error. But at this point, the type annotation on the left hand side is no longer necessary. So you can simplify it to

const apply1 = <X, Y>(f: F<X, Y>, x: X): Y => f(x)

Further reading

Avik Chaudhuri wrote a short explanation on a similar stack overflow question, which in turn links to a similar answer on GitHub

like image 101
Gabe Levi Avatar answered Dec 07 '25 21:12

Gabe Levi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!