Я рекомендую изменить E<W>
на что-то вроде этого:
type E<W> = never extends A<infer T> ? [W] extends [T] ? A<W> : void : never
Сначала условный тип, в котором проверяемый тип равен any
, например any extends X ? Y : Z
, будет оцениваться как союз Y | Z
для большинства типов X
. То есть any
имеет специальный случай, чтобы взять обе ветви условного типа. См. microsoft / TypeScript # 27418 , чтобы обсудить это. Предполагая, что вы пытаетесь использовать только истинную ветвь условного типа, было бы лучше использовать never extends X ? Y : Z
. Как правило, never extends X
всегда будет истинным, и тогда результат будет Y
. Кроме того, если есть тип, который вы не хотите беспокоиться о беспорядке в ваших профсоюзах, вы должны сделать его never
, а не void
. Тип A | never
оценивается как A
, тогда как A | void
обычно нет.
Итак, давайте изменим type E<W> = any extends A<infer T> ? W extends T ? A<W> : void : void
на type E<W> = never extends A<infer T> ? W extends T ? A<W> : void : never
.
Теперь вопрос, который остается является: что вы хотите сделать, когда W
сам по себе является типом объединения? Если вы оставите E<W>
, определенный с W extends T
вместо [W] extends [T]
, он будет рассматриваться как дистрибутивный условный тип . Это означает, что если W
является типом объединения, таким как A | B | C
, то E<W>
оценит условное выражение для каждого члена этого объединения и объединит результаты, что даст эквивалент E<A> | E<B> | E<C>
. Может быть, это то, что вы хотите, но, вероятно, нет. В конце концов, если W
равно string | number
, вы, вероятно, хотите, чтобы void
выходило, а не A<string> | void
, верно?
Правило, когда условные типы становятся дистрибутивными, заключается в том, что вы проверяете «голый» "или" голый "параметр типа generi c. Поскольку W
является универсальным параметром типа c, условный тип W extends T ? ...
будет дистрибутивным. Самый простой способ отключить это поведение - «одеть» параметр типа чем-то ковариантным, например, типом одноэлементного кортежа. Так что это становится [W] extends [T] ? ...
.
Хорошо, надеюсь, это поможет; удачи!
Детская площадка ссылка на код