машинопись: Infer generi c требование типа - PullRequest
0 голосов
/ 08 апреля 2020

Вопрос

Как вы выводите универсальное c требование (что входит в часть расширения) универсального c класса?

Объяснение

// UserGivenClassThatCouldHaveAnyGeneric
class A<T extends string> {
  constructor(a: T) {}
}

Как бы я понял, что родовой c T должен простираться string. Мне нужна эта информация в условном утверждении.

Я пробовал следующее

type E<W> = any extends A<infer T> ? W extends T ? A<W> : void : void

E должно быть недействительным, если дано W не расширяет то, что требуется T , но должен быть, когда это произойдет. Однако это не работает вообще, событие, хотя не отображается предупреждение об ошибке синтаксиса.

1 Ответ

1 голос
/ 09 апреля 2020

Я рекомендую изменить 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] ? ....


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

Детская площадка ссылка на код

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...