Строгий режим это опция "strict": true в tsconfig.json. Это один переключатель для восьми флагов проверки типов, которые ловят неявный any, непроверенные null и undefined, небезопасное присвоение функций и неинициализированные поля классов. В TypeScript 7 strict включён по умолчанию. Вот как выглядит код, который проходит эту проверку:
Вывод: no user, SyntaxError и 42. Уберите : number, ?. или проверку instanceof, и файл перестанет компилироваться.
Как включить
{
"compilerOptions": {
"strict": true
}
}
Отдельные флаги важнее strict в любую сторону. "strict": true, "strictNullChecks": false оставляет всё, кроме проверки null; "strict": false, "noImplicitAny": true включает только один этот флаг. strict также подключает проверки, которые появятся в будущих версиях, потому что новые флаги строгого семейства добавляются в группу.
strict в TypeScript не имеет отношения к директиве "use strict" из JavaScript, которая задаёт режим во время выполнения. TypeScript 7 всегда генерирует "use strict" там, где это нужно, а настройка alwaysStrict: false даёт ошибку TS5108 (опция удалена).
Что ловит каждый флаг
| Флаг | О чём сообщает | Ошибка |
|---|---|---|
noImplicitAny | параметр или переменная, тип которых незаметно стал бы any | TS7006 Parameter 'x' implicitly has an 'any' type. |
strictNullChecks | использование значения, которое может быть null или undefined | TS18048 'u' is possibly 'undefined'. |
strictFunctionTypes | присвоение функции, тип параметра которой уже требуемого | TS2322 |
strictBindCallApply | неверные аргументы для .call, .bind и .apply | TS2345 |
strictPropertyInitialization | поле класса, которому никогда не присваивается значение | TS2564 Property 'name' has no initializer and is not definitely assigned in the constructor. |
noImplicitThis | this с неявным типом any, как во вложенной function | TS2683 |
useUnknownInCatchVariables | использование переменной catch до сужения (её тип unknown) | TS18046 'err' is of type 'unknown'. |
strictBuiltinIteratorReturn | обращение к it.next().value встроенного итератора так, будто значение всегда определено | TS2322 |
Больше всего кода меняют noImplicitAny и strictNullChecks. Этот блок нарушает оба намеренно:
Он выводит index.ts(2,17): error TS7006: Parameter 'x' implicitly has an 'any' type. и index.ts(11,13): error TS18048: 'user' is possibly 'undefined'. Без strict этот код компилируется, а затем падает во время выполнения с TypeError: Cannot read properties of undefined (reading 'name'). Со strict падение превращается в ошибку компиляции. Исправления показаны в первом блоке на этой странице.
strictFunctionTypes: зачем он нужен
Функцию, которая умеет работать только со строками, нельзя использовать там, куда могут прийти числа. Проверка ниже заглушена через @ts-expect-error, чтобы вы могли запустить код и увидеть, от чего защищает ошибка:
Без комментария присвоение даёт ошибку TS2322, Type '(s: string) => void' is not assignable to type 'Handler'., а следом Types of parameters 's' and 'value' are incompatible. Одно исключение оставлено намеренно: параметры методов, объявленных синтаксисом методов (handle(value: string | number): void внутри интерфейса), по-прежнему проверяются мягче, так что shout можно было бы присвоить такому методу без ошибки.
strictPropertyInitialization
Каждое поле класса должно получить значение в объявлении или в конструкторе. Три способа это выполнить:
Вывод:
Account {
owner: 'Ada',
balance: 0,
history: [],
lastLogin: undefined,
sessionId: 's-1'
}
Свойства lastLogin и sessionId существуют со значением undefined, потому что при target ES2022 поля классов это настоящие поля JavaScript. ! убирает проверку, не добавляя никакой защиты во время выполнения, поэтому лучше использовать другие формы. Этому флагу нужен strictNullChecks; если его выключить, отключится и этот.
Как включить strict в существующем проекте
Если перевести большую кодовую базу на strict за один раз, могут появиться сотни ошибок. Поскольку в TypeScript 7 strict включён по умолчанию, обновление проекта, в tsconfig.json которого strict никогда не упоминался, само его включит; напишите "strict": false, если на время миграции нужно старое поведение. Путь, при котором сборка остаётся зелёной:
- Добавьте
"strict": trueи выключите флаги с наибольшим числом ошибок, обычно"strictNullChecks": falseи"noImplicitAny": false. - Исправьте оставшиеся ошибки, затем включите ещё один флаг и повторите.
- Для
noImplicitAnyбольшинство исправлений это аннотации параметров. ДляstrictNullChecksдобавьте| undefinedтам, где значения могут отсутствовать, а затем обработайте это через?.,??или проверкуif. - Где исправление придётся отложить, поставьте на строку
// @ts-expect-errorс указанием причины. В отличие от@ts-ignore, он сообщает об ошибке, как только проблема исчезла, так что список сокращается сам.
Не заглушайте ошибки массово через as any или !: каждое такое место скрывает ровно ту ошибку, ради поиска которой добавлен флаг.
Полезные флаги, которых нет в strict
Они отдельные, потому что отвергают код, который часто корректен. Многие проекты всё равно их включают.
| Флаг | Что делает |
|---|---|
noUncheckedIndexedAccess | arr[i] и record[key] включают undefined в свой тип |
exactOptionalPropertyTypes | debug?: boolean допускает отсутствие ключа, но не debug: undefined |
noImplicitReturns | каждая ветка функции с возвращаемым значением должна что-то возвращать (TS7030) |
noImplicitOverride | метод, переопределяющий метод базового класса, должен быть помечен override (TS4114) |
noFallthroughCasesInSwitch | непустой case должен заканчиваться break, return или throw (TS7029) |
noUnusedLocals, noUnusedParameters | неиспользуемые переменные и параметры считаются ошибками |
noPropertyAccessFromIndexSignature | ключи из индексной сигнатуры нужно читать через obj["key"], а не obj.key |
Больше всего реальных ошибок ловит noUncheckedIndexedAccess. С ним:
const scores = [90, 85];
const d: Record<string, number> = {};
const third: number = scores[2]; // error TS2322: Type 'number | undefined' is not assignable to type 'number'.
const c: number = d["x"]; // same error
const safe = scores[2] ?? 0; // number
for (const s of scores) { // for...of is not affected: s is number
console.log(s);
}
tsc --init в TypeScript 7 включает noUncheckedIndexedAccess и exactOptionalPropertyTypes в генерируемом конфиге рядом со strict.
Часто задаваемые вопросы
Что делает строгий режим в TypeScript?
"strict": true включает группу более строгих проверок: noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitThis, useUnknownInCatchVariables и strictBuiltinIteratorReturn. Вместе они не дают any появляться незаметно и делают null и undefined частью системы типов.
Включён ли строгий режим в TypeScript по умолчанию?
В TypeScript 7 да: strict по умолчанию равен true, так что проект без настройки strict получает все строгие проверки. tsc --init к тому же явно записывает "strict": true. Чтобы отказаться, нужно написать "strict": false.
Можно ли отключить одну строгую проверку, оставив остальные?
Да. Отдельные флаги переопределяют strict: { "strict": true, "strictNullChecks": false } оставляет все строгие проверки, кроме проверки null. Обычно именно так большую кодовую базу переводят по одному флагу за раз.
Строгий режим TypeScript это то же самое, что "use strict" в JavaScript?
Нет. "use strict" это режим JavaScript во время выполнения, который меняет поведение кода. strict в TypeScript меняет только то, о чём сообщает проверка типов. TypeScript 7 всегда генерирует "use strict" для немодульного вывода, а alwaysStrict: false теперь удалённая опция.
Входит ли noUncheckedIndexedAccess в strict?
Нет. noUncheckedIndexedAccess, exactOptionalPropertyTypes, noImplicitReturns, noImplicitOverride и noFallthroughCasesInSwitch это отдельные флаги, которые вы включаете сами. tsc --init включает первые два в генерируемом конфиге.