Как сделать обобщенную функцию с аргументами того же типа, используя обобщение Flow

1

Я пытаюсь сделать типизированную оболочку вокруг функции lodash isEqual. Я хочу, чтобы он работал только для двух аргументов одного типа. У меня есть следующий код:

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)

Но это не сработает, потому что можно передать ему два аргумента разных типов, и Flow отлично справляется с этим. Каков правильный способ реализации такой функции?

Я использую Flow version 0.58.0

  • 0
    Это не должно работать по другой причине: когда T может быть любого типа, не существует единственной функции, которая могла бы осмысленно проверять равенство для всех возможных типов (если вы не готовы полагаться на равенство ссылок в большинстве случаев). Вам понадобится перегруженная функция равенства, и система типов должна будет гарантировать, что экземпляр этой функции существует для определенного типа. Этот вид полиморфизма обычно называют ограниченным полиморфизмом.
  • 0
    @ftor Да, вы правы, на самом деле невозможно определить функцию равенства с помощью сигнатуры, которую я использую. Но это не совсем то, о чем я спрашиваю. Мне нужно определить функцию с двумя аргументами одного типа. Предположим, для простоты, что мне нужно ссылочное равенство (поэтому тело функции будет a === b ). Как я могу это определить?
Показать ещё 1 комментарий
Теги:
generics
flowtype

1 ответ

1
Лучший ответ

После небольшого исследования я могу объяснить, что вызывает такое поведение. T неявно расширяется до типа isEqual<string|number>(a: string|number, b: string:number). Я не могу сказать, почему, но это описано на github.

Из примера в комментарии github выше я извлек решение (или, скорее, взломать), используя фантомный тип 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

Попробуйте.

Существует, вероятно, менее беспорядочное решение, но по-прежнему жаль, что поток не просто объединяет переменные типа с тем же именем и в пределах одной области с одним и тем же типом.

  • 0
    Вау! Спасибо! Я не уверен, что собираюсь использовать это решение, оно выглядит слишком сложным, но, похоже, оно решает мою проблему.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню