ЯдроКодаподготовка к экзаменам
Научная библиотека

Загружаем научный разбор

Подготавливаем текст, источники и редакционные примечания без изменения разметки страницы.

Каталог статейМатериал и источники

Что означает «TypeScript обнаруживает 15% ошибок»: критическое чтение исследования ICSE 2017

Автор: · Обновлено

Критический разбор ICSE 2017: 400 исторических ошибок, Flow 0.30 и TypeScript 2.0, обнаружимость 15%, ограничения метода и собственный протокол оценки пользы типов.

Число «15%» легко превращается в обещание: подключим TypeScript и получим на пятнадцать процентов меньше ошибок. Однако для такого вывода нужно знать, что считали ошибкой, как применяли инструмент и какие условия сравнивали. Доля обнаруженных исторических дефектов, снижение числа новых дефектов и экономия времени команды — разные измеряемые величины. Одна не подменяет другую даже тогда, когда все они связаны с полезностью типов.

Разберём конкретную научную публикацию и построим собственный способ использовать её результат при выборе инструментов. Это авторский аналитический материал, а не перевод статьи и не новая репликация её эксперимента. Наши короткие примеры ниже иллюстрируют границы проверки; они не образуют статистическую выборку. Прикладные основания выбора языка разобраны в [уроке JavaScript или TypeScript](/lessons/typescript/typescript-for-developers/typescript-language-choice).

Что именно опубликовано и измерено

Zheng Gao, Christian Bird и Earl T. Barr представили *To Type or Not to Type: Quantifying Detectable Bugs in JavaScript* на ICSE 2017, страницы 758–769, DOI 10.1109/ICSE.2017.75. Это рецензируемая конференционная работа. Университетский репозиторий UCL подтверждает библиографию и отдельно обозначает размещённый там текст как принятую авторскую версию. Карточка UCL.

Авторы изучили 400 публичных ошибок JavaScript из историй проектов GitHub. Они возвращались к коду перед исправлением, вручную добавляли согласованные аннотации и проверяли диагностику Flow 0.30 и TypeScript 2.0. После разбора оставшихся неопределённых случаев каждый инструмент обнаружил 60 ошибок, то есть 15%; объединение результатов составило 63 ошибки. Поэтому проценты двух инструментов складывать нельзя. Первичный текст исследования, разделы II–IV.

Критерий требовал аннотаций, совместимых с намеренным корректным поведением. Нельзя специально объявить число строкой лишь для получения ошибки компилятора. Метод использовал известное исправление для локализации анализа; среди ограничений авторы обсуждают выбранный корпус публичных ошибок, ручную интерпретацию и возможный пропуск полезных аннотаций вне области исправления. Работа оценивает обнаружимость в таком протоколе, а не причинный эффект внедрения инструмента в случайно выбранную команду. Первичный текст, разделы II и VI.

Знаменатель важнее звучного процента

Рассмотрим собственный мысленный пример. Команда за месяц допустила сто промежуточных ошибок в редакторе, исправила восемьдесят до коммита, ещё пятнадцать заметила на ревью и пять выпустила. Доля предупреждений среди всех промежуточных ошибок и доля среди пяти выпущенных считаются по разным наборам. Инструмент может быть полезным на первом этапе, хотя почти не находит ошибок из последнего набора. Возможна и обратная ситуация.

Эти числа придуманы только для объяснения знаменателя. Они не описывают выборку Gao и коллег и не являются оценкой типичной команды. Их задача — показать, почему перед переносом процента нужно назвать популяцию. Публичный исправленный дефект наблюдаем в истории, а ошибка, удалённая разработчиком до сохранения файла, может не оставить следа. Смешав эти уровни, мы начнём оценивать разные процессы одним числом.

Для решения о проекте полезно сначала задать собственный вопрос. «Какие из недавних инцидентов могли бы дать типовую диагностику?» подходит для ретроспективного разбора. «Станут ли новые задачи выполняться быстрее?» требует наблюдать разработку. «Уменьшится ли ущерб от ошибок?» требует учитывать тяжесть и пользователей. Ни один из вопросов не исчерпывается общим числом срабатываний компилятора.

Обнаружить, исправить и предотвратить — три шага

Предупреждение инструмента становится предотвращённой ошибкой только при дополнительных условиях. Проверка должна запускаться до релевантной границы выпуска, сообщение должно относиться к дефекту, разработчик должен понять его и выполнить корректное исправление. Если команда постоянно подавляет диагностику или проверяет лишь часть файлов, сама выразительность системы типов не обеспечивает этот путь.

Представим два процесса с одинаковым кодом. В первом проверка типов блокирует сборку и поддерживается в рабочем состоянии. Во втором накоплено несколько тысяч предупреждений, а новый сигнал теряется среди старых. Сравнение только версии TypeScript пропустит существенную разницу. Это наш вывод о применении инструмента: результат зависит не только от способности обнаружить нарушение, но и от организации обратной связи.

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

Собственный пример: нарушение формы и нарушение смысла

Проверим две разные ошибки в небольшом расчёте количества страниц. Предметное требование: положительное число элементов делится на положительный размер страницы с округлением вверх. Сначала нарушим тип аргумента, затем формулу. Примеры рассчитаны на проверку TypeScript со strict и не используют исторический компилятор 2.0.

function pageCount(total: number, pageSize: number): number {
  return Math.ceil(total / pageSize);
}
// @ts-expect-error: строка не соответствует договору параметра
const rejected = pageCount('21', 10);

function wrongPageCount(total: number, pageSize: number): number {
  return Math.floor(total / pageSize);
}
console.log(pageCount(21, 10), wrongPageCount(21, 10)); // 3 2

Первая ошибка диагностируется благодаря явному договору числовых параметров. Во втором случае все типы согласованы, но результат нарушает условие задачи. Для него нужен содержательный тест, например ожидаемое значение 3 для 21 элемента. Так можно увидеть различие механизмов без обобщения по единственному примеру. Компилятор проверяет форму допустимых операций, тест наблюдает выбранное поведение.

Дополнительно есть нулевой размер страницы и отрицательное количество элементов. Тип number допускает такие значения, а также специальные числовые значения JavaScript. Значит, входные ограничения требуют проверки и ясной политики ошибки. Можно описывать уточнённые модели, но место установления соответствующей гарантии всё равно должно существовать. Называть все ошибки числовой функции «ошибками типов» было бы слишком широким толкованием результата.

Конфигурация меняет проверяемый договор

Даже одинаковая аннотация в разных режимах может дать разную диагностику. Исторические release notes TypeScript 2.0 описывают появление режима strictNullChecks, который отделяет null и undefined от обычных типов. Нельзя читать название версии, не учитывая режим проверки. При воспроизведении исторического результата необходимо сохранить конфигурацию вместе с исходным кодом. TypeScript 2.0: strictNullChecks.

В современном проекте отдельный пример даёт noUncheckedIndexedAccess: обращение к произвольному ключу словаря начинает учитывать отсутствие записи. Это не дополнительная runtime-проверка, а изменение статической информации для вызывающего кода. TSConfig: noUncheckedIndexedAccess.

const pageSizes: Record<string, number> = { compact: 10 };
const selected = pageSizes['unknown'];
// @ts-expect-error: с noUncheckedIndexedAccess возможно undefined
const size: number = selected;
console.log(selected); // undefined

Смена флага может расширить набор предупреждений на выбранном корпусе. Однако нельзя из этого вывести новый процент для всех ошибок: другие дефекты по-прежнему могут находиться за границей типов, а часть предупреждений потребует анализа. Для сравнения версий нужно повторить заранее определённый протокол, указать настройки и показать, какие именно случаи поменяли классификацию.

«Перейти на TypeScript» допускает разные реализации

Вариант с переименованием файлов, большим количеством any и утверждений типа отличается от варианта с проверенными границами данных. Третий путь — проверять существующий JavaScript с JSDoc. Официальная документация описывает особенности проверки .js и отличия от .ts; расширение файла само по себе не характеризует всю строгость анализа. TypeScript: Type Checking JavaScript Files.

Поэтому небольшой пилот следует описывать через конкретные изменения. Например: типизировать входную команду, проверить ответ внешней системы как unknown, убрать подавление в одном критическом модуле и запускать проверку перед слиянием. Тогда понятны и границы работы, и место ожидаемой пользы. Формулировка «внедрили TypeScript на десять процентов» не объясняет, какие гарантии появились у потребителей.

Даже строгая конфигурация не делает TypeScript полностью состоятельной системой доказательства безопасности программ. В документации совместимости открыто описаны практические допущения. Поэтому современный пример с удачной диагностикой не является основанием отменять тесты, проверку внешних данных или ревью предметной логики. TypeScript: A Note on Soundness.

Как провести полезный локальный разбор ошибок

Ниже предложен собственный протокол для учебного или рабочего проекта. Это не описание процедуры авторов ICSE и не её точная репликация. Выберите небольшой период истории до просмотра результатов и включите все подходящие исправления по заранее записанному правилу. Для каждого сохраните версию до исправления, ожидаемое поведение и минимальный воспроизводимый сценарий. Не удаляйте неудобные случаи молча: фиксируйте причину исключения.

Затем попробуйте выразить договор без изменения алгоритма. Проверяйте, относится ли диагностика к изучаемой ошибке, а не к несовместимости старой зависимости. Отдельно записывайте случаи, где решение осталось неясным. Полезно дать второму человеку независимо прочитать несколько примеров: расхождение покажет, какие формулировки требований слишком расплывчаты. Такой контроль улучшает собственный анализ, даже если выборка слишком мала для статистического обобщения.

Итоговая таблица может содержать идентификатор дефекта, нарушенное условие, добавленный договор, диагностируемую строку, затраченное время и оставшийся runtime-тест. Не стоит объединять время установки старого проекта с временем понимания аннотации без отдельного учёта. Это разные расходы, и в будущем проекте они могут соотноситься иначе.

Какой вывод обоснован для обучения

Современные примеры этой статьи автоматически проверены 8 сентября 2026 года на TypeScript 5.9.3 и 6.0.3 с strict, exactOptionalPropertyTypes и noUncheckedIndexedAccess. Отрицательные случаи вызвали диагностику, исполнение вывело 3 2 и undefined. Flow 0.30 и TypeScript 2.0 для этой проверки не запускались; исторические 15% взяты из первичного исследования, а не пересчитаны по нашим двум фрагментам.

Работа 2017 года даёт конкретный пример эмпирического изучения возможностей статической проверки. Её ценность для студента шире одного процента: она заставляет определить наблюдаемую ошибку, договор и критерий полезной диагностики. Собственные три коротких примера из статьи показывают, как задавать эти вопросы, но не заменяют корпус реальных дефектов.

Для продолжения возьмите один баг учебного приложения и оформите мини-отчёт: ожидаемое поведение, ошибка до исправления, информация, доступная типам, и проверка после исправления. [Урок о tsconfig](/lessons/typescript/typescript-for-developers/typescript-tsconfig) поможет зафиксировать режим анализа, [урок об unknown](/lessons/typescript/typescript-for-developers/typescript-any-unknown-never) — честно обозначить неизвестные данные, а [урок о runtime-валидации](/lessons/typescript/typescript-for-developers/typescript-runtime-validation) — установить границу доверия. Вывод должен отвечать за изученный случай и явно оставлять открытым то, что опыт не измерял.

Источники

Формат и права

Формат
Авторский разбор

Атрибуция

Авторский русскоязычный разбор. Перечисленные первичные источники использованы для проверки технических утверждений и библиографии; материал не является переводом или перепечаткой источников. Собственные примеры и рассуждения отделены от опубликованных эмпирических результатов.

Код, данные и иллюстрации

Иллюстрации, таблицы и код первоисточников не воспроизводятся. Примеры и текстовые схемы созданы для этой статьи. Ссылки и библиографические сведения не предоставляют прав на перепубликацию материалов источников.