Ответ вслух Senior Дженерики обновлено

Вариантность в TypeScript

Вопрос

Объясните ковариантность и контравариантность на примере TypeScript. Где TS здесь сознательно нестрог?

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

Вариантность отвечает на вопрос, как подтипы аргумента типа переносятся на составной тип. Если Dog подтип Animal, то readonly Dog[] подтип readonly Animal[]: это ковариантность, значения только «выходят».

Что должно прозвучать в ответе

  • Ковариантность: `Dog[]` можно использовать как `Animal[]`, подтип сохраняется в позиции «выхода»

  • Контравариантность параметров: функция, принимающая `Animal`, подходит туда, где ждут обработчик `Dog`, но не наоборот

  • `strictFunctionTypes` включает это для типов функций, методы остаются бивариантными

  • Массивы ковариантны и при этом изменяемы: запись `Cat` в `Animal[]`, который на деле `Dog[]`, компилятор не поймает

  • Аннотации `in`/`out` (TS 4.7) явно задают вариантность параметров типа

Что могут спросить следом

  • Почему методы оставили бивариантными?
  • Как объявить обработчик событий, чтобы проверка была строгой?
  • Что такое инвариантность и где она встречается?

Разбор

Вариантность отвечает на вопрос, как подтипы аргумента типа переносятся на составной тип. Если Dog подтип Animal, то readonly Dog[] подтип readonly Animal[]: это ковариантность, значения только «выходят». Для параметров функций наоборот: функция (a: Animal) => void безопасно подставляется туда, где ждут (d: Dog) => void, потому что умеет больше. Это контравариантность. TS проверяет её строго только с strictFunctionTypes и только для типов функций; методы бивариантны ради совместимости встроенных типов вроде Array.push. Вторая известная дыра: изменяемые массивы ковариантны, поэтому можно положить кошку в массив собак через ссылку Animal[]. Инвариантный параметр (и вход, и выход, например set и get одного T) не допускает подстановок ни в какую сторону. С TS 4.7 вариантность можно задать явно in/out, это и документация, и ускорение проверки.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.

Термины по теме