Nikolai Mavrenkov
Nikolai Mavrenkov

Reputation: 1923

How to make a generic function with the arguments of the same type using Flow generics

I am trying to make a typed wrapper around lodash's isEqual function. I want it to work only for two arguments of the same type. I have following code:

export function isEqual<T>(a: T, b: T): boolean {
  return _.isEqual(a, b); 
}

const c: boolean = isEqual('one', 2); // shouldn't it be a type error here?
console.log(c)

But it doesn't work, because it's possible to pass two arguments of different types to it and Flow is fine with that. What is a right way to implement such a function?

I am using Flow version 0.58.0

Upvotes: 1

Views: 245

Answers (1)

user6445533
user6445533

Reputation:

After a little research I can explain what causes this behavior. T is implicitly expanded to the union type isEqual<string|number>(a: string|number, b: string:number). I can't tell you why, but it is described on github.

From the example in the github comment above, I extracted a solution (or rather a hack) by using a phantom type P:

type __R<T, T> = T;
type _R<T> = __R<*, T>;

type _Eq<T, U: _R<T>> = (T, U) => boolean;
type Eq<P> = _Eq<*, *>;

const eq:Eq<any> = (a, b) => a === b;

eq(true, false); // type checks

eq(1, 2); // type checks

eq(true, "foo"); // doesn't type check

Try it.

There is probably a less messy solution but it is still a pity that flow doesn't just unify type variables with the same name and within the same scope with the same type.

Upvotes: 1

Related Questions