Как проверить, что типы одинаковы?

#typescript #typescript-generics

Вопрос:

Я хочу проверить, совпадают ли 2 типа. Я ожидал

 export type AreSame<T, U, R> = T extends U ? U extends T ? R : never : never;
 

работать, но на самом деле это не удается в профсоюзах:

 type A = AreSame<1, 1, Object>          // Object
type B = AreSame<1, 2, Object>          // never
type C = AreSame<1, number, Object>     // never
type D = AreSame<1, 1 | 2, Object>      // Object - why???
type E = AreSame<1 | 2, 1 | 3, Object>  // Object - why???
type F = AreSame<1 | 2, 1 | 2, Object>  // Object
 

Как я могу это исправить?

Ответ №1:

Ваши условные типы случайно являются распределительными. Это означает, что в конечном итоге происходит разделение союзов, оценка типа для каждого члена и объединение их обратно вместе. Пожалуйста, ознакомьтесь с этой документацией, потому что это важно. Если у вас есть тип, например type G<T> = T extends U ? X : Y , где T параметр типа «голый» (так что это T extends и не SomethingWith<T> extends так), то он будет распространяться. Иногда это то, чего ты хочешь. Сейчас это не так.

Самый простой способ отключить распределительные условные типы-это «одеть» параметр голого типа: превратиться T extends U ? X : Y в [T] extends [U] ? X : Y . So:

 export type AreSame<T, U, R> = [T] extends [U] ? [U] extends [T] ? R : never : never;

type A = AreSame<1, 1, Object>          // Object
type B = AreSame<1, 2, Object>          // never
type C = AreSame<1, number, Object>     // never
type D = AreSame<1, 1 | 2, Object>      // never
type E = AreSame<1 | 2, 1 | 3, Object>  // never
type F = AreSame<1 | 2, 1 | 2, Object>  // Object
 

Хорошо, надеюсь, это поможет; удачи!

Ссылка на код

Ответ №2:

Я просто высказываю предположение, но если мы считаем, что объединение похоже на логическое или, это имело бы смысл.

Позвольте мне попытаться псевдокодировать шаги, необходимые для ответа на этот вопрос..

 1 extends (1|2) ? (1|2) extends 1 ? Object : never : never // becomes ->
(1 extends 1 || 1 extends 2) ? (1 extends 1 || 2 extends 1) ? : Object : never : never
 

Я бы подумал о проверке кода машинописи, чтобы проверить, как именно он работает..

ИЗМЕНИТЬ: Чтобы решить эту проблему, я нашел эту проблему на github в репозитории машинописных текстов

Лучшим решением здесь является следующее:

 export type Equals<X, Y> =
    (<T>() => T extends X ? 1 : 2) extends
    (<T>() => T extends Y ? 1 : 2) ? true : false;
 

Может быть, вы сможете подогнать это под свой случай? Надеюсь, это поможет 🙂

Комментарии:

1. Это может быть причиной, но что я должен изменить, чтобы это работало так, как мне нужно?