История вопроса
По умолчанию TypeScript допускает определённую "расхлябанность" при сопоставлении типовых сигнатур функций, разрешая, чтобы обратимые и необратимые функции считались совместимыми. Начиная с TypeScript 2.6 появилась опция strictFunctionTypes, гарантирующая строгую проверку типов функций и предотвращающая множество классов ошибок, особенно в крупных кодовых базах.
Проблема
Без строгой проверки возможна ситуация, когда функция-обработчик или колбэк принимает больше или более специфичный тип параметров и это незаметно для разработчика. Это приводит к runtime-ошибкам, связанным с ковариантностью возвращаемых типов и контравариантностью аргументов.
Решение
Опция strictFunctionTypes вводит строгую контравариантность для типов параметров функций. Теперь функции совместимы только если параметр типа источника является супертитом параметра назначения, а не наоборот.
Пример кода:
type Animal = { name: string }; type Cat = { name: string; meow: () => void }; let animalHandler: (a: Animal) => void; let catHandler: (c: Cat) => void; animalHandler = catHandler; // Ошибка при strictFunctionTypes: аргумент слишком специфичен catHandler = animalHandler; // Разрешено, Cat — подтип Animal
Ключевые особенности:
Можно ли было присвоить обработчик с более специфичным типом параметра раньше, до появления strictFunctionTypes?
Да, до активации strictFunctionTypes TypeScript позволял присваивать более специфичные функции вместо общих, что приводило к runtime-problem:
enum E { A, B } const f: (e: E) => void = (e: E.A) => {} // Без strictFunctionTypes: разрешено
Как strictFunctionTypes влияет на колбэки с опциональными параметрами?
Если параметры функции-колбэка делают какие-то параметры опциональными, строгая проверка не позволит использовать функцию с меньшим числом обязательных параметров в позиции, где ожидается функция с большим количеством. Это предотвращает ситуацию, когда callback не получает нужные данные.
Будут ли проблемы совместимости при включении strictFunctionTypes в старых проектах?
Да, есть риск появления новых ошибок компиляции, так как многие функции и обработчики могли быть присвоены друг другу с нарушением контравариантности. Чаще всего это встречается при обратных вызовах или при использовании API сторонних библиотек без строгой типизации.
В большом проекте обработчики событий принимают более специфичные типы (MouseEvent вместо общего Event). Это не обнаруживается до включения строгой опции, приводя к ошибкам при запуске с разными источниками событий.
Плюсы:
Минусы:
Проект использует strictFunctionTypes с самого начала. При добавлении новых обработчиков все расхождения между типами автоматически обнаруживаются компилятором. Код становится устойчивее к опечаткам, поддерживается проще.
Плюсы:
Минусы: