Я пытаюсь сделать типизированную оболочку вокруг функции 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
После небольшого исследования я могу объяснить, что вызывает такое поведение. 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
Существует, вероятно, менее беспорядочное решение, но по-прежнему жаль, что поток не просто объединяет переменные типа с тем же именем и в пределах одной области с одним и тем же типом.
T
может быть любого типа, не существует единственной функции, которая могла бы осмысленно проверять равенство для всех возможных типов (если вы не готовы полагаться на равенство ссылок в большинстве случаев). Вам понадобится перегруженная функция равенства, и система типов должна будет гарантировать, что экземпляр этой функции существует для определенного типа. Этот вид полиморфизма обычно называют ограниченным полиморфизмом.a === b
). Как я могу это определить?