본문 바로가기
C.W.K.
Stream
Lesson 04 of 06 · published

엄격 모드: 처음부터 켜고 빚을 만들지 마

~12 min · foundations, strict-mode, tsconfig, philosophy

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"엄격 모드는 코드를 까다롭게 만드는 벌이 아니라, 타입이 모른다는 사실을 숨기지 못하게 하는 약속이야."

상위 스위치 하나

strict: true는 서로 다른 여러 엄격 검사를 한꺼번에 켜는 상위 설정이야. 암묵적으로 any가 되는 매개변수, null 가능성을 숨긴 값, 잘못 묶인 함수의 this, 초기화하지 않은 클래스 속성처럼 타입 시스템이 조용히 넘어갈 수 있던 틈을 드러내.

새 프로젝트라면 첫 줄부터 켜는 게 가장 싸. 코드가 적을 때 오류의 뜻을 배우며 고치면 되지만, 수만 줄을 쓴 뒤 켜면 그동안 쌓인 가정을 한꺼번에 정산해야 해. 나중에 엄격해지겠다는 계획은 대개 기술 부채에 날짜표만 붙이는 일이 돼.

strict가 켜는 일곱 설정

  • noImplicitAny: 추론할 수 없는 암묵적 any를 막아.
  • strictNullChecks: null과 undefined를 다른 타입에서 분리해.
  • strictFunctionTypes: 함수 매개변수의 안전한 대입 관계를 검사해.
  • strictBindCallApply: call, apply, bind의 인자를 원래 함수 시그니처와 맞춰.
  • strictPropertyInitialization: 클래스 필드가 생성 과정에서 초기화되는지 확인해.
  • noImplicitThis: 타입을 알 수 없는 this를 오류로 만들어.
  • useUnknownInCatchVariables: catch 변수를 any 대신 unknown으로 다루게 해.

엄격하다고 모든 것이 끝나진 않아

상위 설정만으로 켜지지 않는 검사도 있어. noUncheckedIndexedAccess는 배열과 사전의 인덱스 접근에 undefined 가능성을 더하고, exactOptionalPropertyTypes는 속성이 없는 상태와 값이 undefined인 상태를 구별해. 프로젝트의 위험과 이전 코드의 규모에 따라 추가하되, 새 코드라면 더 정직한 쪽에서 시작하는 편이 좋아.

그렇다고 경고를 없애려고 무조건 단언을 덧칠하면 엄격 모드의 뜻이 사라져. !as any는 컴파일러가 틀렸다는 증거가 있을 때 쓰는 비상구야. 오류가 귀찮다는 이유로 비상구를 정문으로 만들면 설정만 엄격하고 실제 코드는 느슨한 이상한 집이 돼.

오류를 설계 피드백으로 읽어

null 오류가 잔뜩 난다면 값의 부재를 데이터 모델이 제대로 표현하지 못했을 수 있어. 암묵적 any가 많다면 함수 경계가 흐리거나 외부 라이브러리의 타입이 비어 있을 수 있지. 엄격 모드는 단지 잘못된 줄을 지적하는 게 아니라, 설계에서 사실을 숨긴 자리를 목록으로 만들어 줘.

TypeScript 4.6부터 tsc --init이 만드는 시작 tsconfig에는 "strict": true가 자동으로 들어가. 처음부터 엄격 모드로 시작하라는 공식 기본값인 셈이야.

엄격 모드의 핵심은 ‘모르면 모른다고 말하기’야. 거짓 확신보다 명시적 불확실성이 낫고, 불확실성을 타입에 드러내야 코드가 확인 절차를 요구할 수 있어.

피파의 고백

엄격 모드가 귀찮았던 순간은 많아도 켜 둬서 후회한 순간은 거의 없었어. 반대로 잠깐 끄고 지나간 자리는 나중에 꼭 이자를 붙여 돌아왔지. 컴파일러가 지금 칭얼대는 편이 운영 중 사용자가 대신 울게 만드는 것보다 훨씬 싸.

Code

strict: true 전개 — 실제로 켜는 것·json
// tsconfig.json — 옳은 모양
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "strict": true,
    // `strict: true` 가 켜는 7개 flag (그 외엔 default false):
    //   "noImplicitAny": true,
    //   "strictNullChecks": true,
    //   "strictFunctionTypes": true,
    //   "strictBindCallApply": true,
    //   "strictPropertyInitialization": true,
    //   "noImplicitThis": true,
    //   "useUnknownInCatchVariables": true,
    "outDir": "./dist"
  }
}
Strict mode 가 잡는 것·typescript
// strictNullChecks 없으면 (위험):
function getInitial(name: string) {
  return name[0].toUpperCase();           // ✅ 컴파일 — 근데 name 이 undefined 면?
}

// strictNullChecks 있으면:
function getInitialSafe(name: string | undefined) {
  return name[0].toUpperCase();           // ❌ 'name' is possibly undefined
  // 처리하라고 강제됨:
  // if (name === undefined) return '?';
  // return name[0].toUpperCase();
}

// noImplicitAny 없으면:
function add(a, b) { return a + b; }      // ✅ 컴파일 — `a` 도 `b` 도 implicit any

// noImplicitAny 있으면:
function addSafe(a, b) { return a + b; }  // ❌ Parameter 'a' implicitly has 'any' type
// Annotate 강제됨:
// function addSafe(a: number, b: number): number { return a + b; }

External links

Exercise

이전 레슨의 작은 TypeScript 프로젝트에서 tsconfig의 strict를 먼저 false로 설정해. 타입을 적지 않은 매개변수의 프로퍼티에 접근하는 함수를 작성한 다음 stricttrue로 바꿔 새 오류가 몇 개 생기는지 세어 봐. 그 오류들을 하나씩 고치며 같은 코드의 계약이 어떻게 더 안전해지는지 확인해.
Hint
오류가 거의 없다면 nullable 반환값이나 타입 없는 매개변수 같은 위험한 예를 더해. 어떤 엄격성 옵션이 각각의 가정을 드러내는지 확인해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고
💛 by 똘이warm

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.