타입스크립트 교재 · 18편 / 20편

strict 모드 깊게 — 7가지 옵션 + 보너스

strict 가족이 켜는 검사들과 추가로 켤 값진 옵션 3개.

고급읽는 시간 7분2026-05-17
strict 옵션이 다양한 타입 안전 검사를 켜는 토글 도식

strict: true 한 줄이 7가지 검사를 동시에 켭니다. 각각이 어떤 버그를 잡는지 알면 어떤 strict 옵션을 켤지·끌지 판단하기 쉽습니다. 18편은 strict 7가족을 하나씩 풀고, 그 위에 추가로 켜면 좋은 옵션 3개까지.

strict — 7가지 옵션을 한 번에

{
  "compilerOptions": {
    "strict": true
    // = strictNullChecks
    // + noImplicitAny
    // + strictFunctionTypes
    // + strictBindCallApply
    // + strictPropertyInitialization
    // + noImplicitThis
    // + useUnknownInCatchVariables
    // + alwaysStrict
  }
}

① strictNullChecks — 가장 중요

// 끄면 — null/undefined 가 어디든 들어감 (위험)
function len(s: string) { return s.length; }
len(null);   // 컴파일 통과 → 런타임 에러

// 켜면 — null/undefined 는 명시적으로
function len(s: string | null) {
  if (s === null) return 0;
  return s.length;
}

strict 가족 중 가장 큰 가치. "이 변수가 null 일 수 있나" 가 타입에 보입니다.

② noImplicitAny — 타입 적게 빠뜨리기

// 끄면
function add(a, b) { return a + b; }    // a, b 는 any
add("1", 2);   // 통과

// 켜면 — 매개변수에 타입 강제
function add(a: number, b: number) { ... }   // 안 적으면 에러

③ strictFunctionTypes — 함수 매개변수 변성

// Animal 받는 함수에 Dog 받는 함수 할당?
// 끄면 통과, 켜면 막힘 (안전)

type AnimalHandler = (a: Animal) => void;
type DogHandler    = (d: Dog) => void;

let h: AnimalHandler = (d: Dog) => { ... };
// 끄면 OK — 하지만 h(cat) 했을 때 d.bark() 호출하면 런타임 에러
// 켜면 에러로 차단

④ strictPropertyInitialization — 클래스 필드 초기화

// 끄면
class User {
  name: string;     // 초기값 없음 → 사용 시 undefined
}

// 켜면
class User {
  name: string;     // ❌ 'name' has no initializer

  // 해결 1: 초기값
  name: string = "";

  // 해결 2: 생성자에서
  constructor(name: string) { this.name = name; }

  // 해결 3: ! (확실히 나중에 할당함을 약속)
  name!: string;
}

⑤ noImplicitThis — this 의 타입

// 끄면 this 가 any
function fn() {
  console.log(this.x);    // any
}

// 켜면 — 일반 함수의 this 는 사용 전 명시 필요
function fn(this: { x: number }) {
  console.log(this.x);    // OK
}

⑥ useUnknownInCatchVariables — catch 의 안전

try { ... } catch (err) {
  // 끄면 err: any (위험)
  // 켜면 err: unknown — 검사 후 사용
  if (err instanceof Error) console.error(err.message);
}

⑦ strictBindCallApply — bind/call/apply 의 타입 검사

function greet(name: string) { return `Hi, ${name}`; }
greet.call(null, 42);   // 끄면 통과, 켜면 에러 (number !== string)

보너스 1 — noUncheckedIndexedAccess

"noUncheckedIndexedAccess": true

const arr = [1, 2, 3];
const x = arr[10];    // 끄면 x: number (거짓말), 켜면 x: number | undefined

if (x !== undefined) {
  x.toFixed(2);       // OK
}

// Record 인덱스도
const map: Record<string, number> = { a: 1 };
const v = map["b"];   // 켜면 v: number | undefined

가장 중요한 보너스. strict 만으로는 배열·객체 인덱스 접근이 항상 값이 있는 것처럼 다룸. 이 옵션이 그 거짓말을 막아줍니다. 약간 짜증나지만 진짜 버그 잡습니다.

보너스 2 — exactOptionalPropertyTypes

"exactOptionalPropertyTypes": true

interface Config {
  port?: number;
}

// 끄면
const c: Config = { port: undefined };   // OK

// 켜면
const c: Config = { port: undefined };
// ❌ Type 'undefined' is not assignable to type 'number'
// → 명시적으로 undefined 보내려면 port?: number | undefined 로 정의해야

"?"(있음/없음) 와 "undefined"(값으로 undefined) 의 구분. JSON·API 응답 다룰 때 의미 있는 차이.

보너스 3 — noImplicitOverride

"noImplicitOverride": true

class Cat extends Animal {
  speak() { ... }            // ❌ Must use 'override' modifier
  override speak() { ... }   // ✅
}

부모 메서드 오버라이드할 때 명시. 부모 메서드 이름이 바뀌면 자식에서 컴파일 에러로 즉시 알림.

실전 단계별 도입

단계설정대상
0strict: false옛 JS 코드 마이그레이션 시작
1noImplicitAny: true매개변수 타입 채우기
2strictNullChecks: truenull 처리 정리
3strict: true새 코드의 표준
4+ noUncheckedIndexedAccess진짜 안전 (배열/Record)
5+ exactOptionalPropertyTypes미세 안전 (선택)
6+ noImplicitOverride상속 안전

점진 도입 가이드. 기존 코드 베이스가 크면 한 번에 strict 켜지 말고 위 단계대로. 각 단계마다 발생한 에러를 정리한 다음 다음 옵션. strict-only 디렉터리부터 시작해 단계적으로 확장도 OK.

19편 — 빌드 성능 (incremental·project references)

모노레포·큰 프로젝트의 빌드 시간 줄이기.

📚 쉽게 배우는 타입스크립트 교재
이전: 17편 .d.ts · 현재: 18편 (고급) · 다음 → 19편 빌드 성능 · 진행: 18/20

© 2026 주나이테크(주) @JUNAITECH