Why could not useCallback accept a generic type instead of callback type?

The current useCallback accepts a callback type ('input => 'output) as a first argument.
Due to this a function with labeled arguments could not be passed to useCallback.
Instead, if the callback type is generic then function could have labeled arguments
eg:

@module("react")
external useCallback2: ('a, ('b, 'c)) => 'a = "useCallback"

let a = useCallback2((~a, ~b) => a + b, (1, 2))

This would also not cause any issues if we pass anything other than function. Because React does not call the callback function.

I guess first you wouldn’t be able to understand the usage from the signature and secondly you can’t use @uncurry in the bindings as it is today.

The authors of rescript-react could probably tell you more.

Why is uncurry necessary here?

The solution you proposed above would allow any value to be passed to useCallback:

@module("react")
external useCallback2: ('a, ('b, 'c)) => 'a = "useCallback"

// This compiles, even if it shouldn't
let a = useCallback2(1, (1, 2))

Unless I am missing something obvious regarding useCallback usage?

1 Like

Yeah It compiles. But it does not create a run time error.

Because React does not call this function ( the value which we gave as an argument).

We would be using the returned callback in rescript. Which would throw a compile error if it is not a function and we try to call it.

Just now checked in the react codebase. The callback argument is a generic type.

Actually we need this change (accept a generic type instead of a callback type) anyway for compatibility with ReScript 11 uncurried mode. As there is no way to express the type “an (uncurried) function of any arity”.

I just made the change here: Compatibility with ReScript 11 uncurried mode by cknitt · Pull Request #90 · rescript-lang/rescript-react · GitHub

2 Likes