TypeScriptMiddleTechnical

Что дают noUncheckedIndexedAccess, exactOptionalPropertyTypes и strict-режим в tsconfig?

strict включает базовый набор проверок; noUncheckedIndexedAccess добавляет | undefined при индексном доступе к массивам и Record; exactOptionalPropertyTypes запрещает явный undefined там, где свойство просто необязательно.

strict-режим в tsconfig

Флаг "strict": true включает сразу несколько проверок одним ключом: strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitAny, noImplicitThis, alwaysStrict и useUnknownInCatchVariables. Это базовая линия безопасности для любого нового проекта.

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true
  }
}

noUncheckedIndexedAccess

Без этого флага TypeScript считает, что обращение к массиву или Record по индексу всегда возвращает элемент нужного типа. Это неверно — индекс может выйти за границы.

const arr: string[] = ['hello'];

// Без noUncheckedIndexedAccess:
const s: string = arr[99]; // компилятор молчит, runtime — undefined

// С noUncheckedIndexedAccess:
const s2 = arr[99]; // тип: string | undefined
const len = s2.length; // Ошибка: Object is possibly 'undefined'
const len2 = s2?.length; // OK

Аналогично для Record<string, T>:

const map: Record<string, number> = {};
const val = map['missing']; // number | undefined — безопаснее

exactOptionalPropertyTypes

По умолчанию TypeScript разрешает явно присвоить undefined необязательному свойству, хотя семантически это разные вещи: свойство «отсутствует» vs свойство «присутствует со значением undefined».

interface Config {
  timeout?: number; // означает: число ИЛИ свойство не существует
}

// Без exactOptionalPropertyTypes — оба варианта OK:
const c1: Config = { timeout: undefined }; // присвоено undefined
const c2: Config = {};                      // свойство отсутствует

// С exactOptionalPropertyTypes:
const c3: Config = { timeout: undefined }; // Ошибка!
// Type 'undefined' is not assignable to type 'number'
const c4: Config = {};                      // OK

// Чтобы разрешить undefined явно — укажите union:
interface Config2 {
  timeout?: number | undefined;
}

Это критично при работе с Object.assign, spread и Partial<T> — без флага можно случайно «затереть» существующее свойство через явный undefined.

Сравнение и когда включать

  • strict — включать всегда на новых проектах.
  • noUncheckedIndexedAccess — включать если важна корректность работы с коллекциями; на легаси-коде может дать много предупреждений сразу.
  • exactOptionalPropertyTypes — включать если код активно использует необязательные свойства и важно различать «нет свойства» и «свойство = undefined»; хорошо сочетается с Zod/Valibot-схемами.

Подводные камни

  • noUncheckedIndexedAccess ломает for-of безопасным способом — итерация через индекс (arr[i]) потребует проверки, хотя for-of сам по себе гарантирует существование элемента.
  • Partial<T> + exactOptionalPropertyTypesPartial<T> генерирует prop?: T[K] без | undefined, что означает: явное undefined снова запрещено в Partial-объектах.
  • Миграция существующей кодовой базы — включение этих флагов на большом проекте может выдать сотни ошибок одновременно; лучше включать постепенно через @ts-expect-error.
  • Взаимодействие с библиотеками — типы из @types/* не всегда написаны с учётом exactOptionalPropertyTypes и могут конфликтовать.
  • noUncheckedIndexedAccess не охватывает деструктуризациюconst [first] = arr не добавляет | undefined к first, только прямой индекс.
  • Ложная строгость с tuples — для tuple типов TypeScript знает длину, но noUncheckedIndexedAccess всё равно добавляет | undefined при доступе через переменный индекс.
  • strict не включает noUncheckedIndexedAccess и exactOptionalPropertyTypes — это отдельные флаги, которые нужно добавлять явно даже при "strict": true.

Common mistakes

  • Отвечать определением без production-сценария.
  • Не называть runtime boundary, security boundary или failure mode.
  • Игнорировать версию API, observability и тестовую проверку.

What the interviewer is testing

  • Объясняет механизм своими словами и без выдуманных API.
  • Называет реальные риски, диагностику и критерий корректности.
  • Связывает ответ с текущей документацией и миграционными ограничениями.

Sources

Related topics