TypeScript의 strict는 boolean 하나처럼 보이지만 여러 검사를 한꺼번에 켜. 오류 메시지가 가리키는 검사를 알면 타입 체커와 싸우지 않고 버그를 고칠 수 있어.
strict: true가 켜는 검사
strict를 켜면 서로 관련된 엄격한 검사가 함께 적용돼. 전부 외울 필요는 없지만 오류가 어느 규칙에서 왔는지 알면 해결 방향을 잡기 쉬워.
noImplicitAny는 추론할 수 없는 값이 조용히any가 되지 않게 해.strictNullChecks는null과undefined를 다른 값과 구분하게 해.strictFunctionTypes는 함수 인자의 호환성을 더 안전하게 검사해.strictBindCallApply는bind,call,apply에 넘긴 인자도 확인해.strictPropertyInitialization는 클래스 필드가 생성 과정에서 초기화되는지 검사해.noImplicitThis는 타입을 알 수 없는this를 막아.alwaysStrict는 strict mode로 파일을 해석하고 출력하게 해.useUnknownInCatchVariables는 catch의 오류 값을any대신unknown으로 다루게 해.
strict: true가 없어도 먼저 버전을 확인해. TypeScript 6.0부터 strict가 기본값이어서 최신 Vite 템플릿에는 중복된 줄이 없을 수 있어. 예전 프로젝트에 명시된 설정은 그대로 두면 돼.React 프로젝트에서 함께 볼 설정
jsx: react-jsx는 최신 JSX transform을 사용하게 해. moduleResolution: bundler는 Vite와 같은 방식으로 import를 해석해. target: ES2022 이상이면 top-level await와 비공개 클래스 필드 같은 현대 문법을 불필요하게 낮추지 않아.
설정 파일이 나뉘는 이유
tsconfig.json은 다른 설정을 가리키는 시작점이고, tsconfig.app.json은 브라우저에서 실행할 src/ 코드를 검사해. tsconfig.node.json은 Node에서 실행되는 Vite 설정을 맡아. 실행 환경이 다르므로 필요한 라이브러리 타입도 달라.
오류 메시지를 해결하는 순서
string | undefined를 string 자리에 넘길 수 없다는 오류가 보이면 먼저 값이 있는지 검사해 타입을 좁혀. 기본값을 주거나 함수가 undefined를 받도록 계약을 넓히는 방법도 있어. 실제 검증 없이 non-null assertion인 !로 숨기면 런타임 오류 가능성은 그대로 남아.
각 strict 검사가 실제로 막는 버그
noImplicitAny는 타입을 잃은 이벤트 인자가 코드 전체로 퍼지는 일을 막아. strictNullChecks는 아직 오지 않은 API 응답을 이미 있는 값처럼 쓰지 못하게 하고, strictFunctionTypes는 더 좁은 입력만 처리하는 함수를 넓은 콜백 자리에 잘못 넘기는 일을 잡아. useUnknownInCatchVariables 덕분에 오류를 문자열이라고 가정하기 전에 instanceof Error 같은 검사가 필요해.
strictPropertyInitialization은 생성자가 끝난 뒤에도 비어 있을 수 있는 클래스 필드를 알려 줘. strictBindCallApply는 함수의 원래 시그니처와 다른 인자를 bind·call·apply에 넘기는 실수를 막고, noImplicitThis는 콜백 안의 this가 어느 객체인지 모호한 코드를 거부해.
브라우저 코드와 Node 설정을 나누는 이점
앱 설정에는 DOM 타입이 필요하지만 vite.config.ts에는 Node 타입이 필요해. 두 환경을 한 tsconfig에 섞으면 브라우저 코드에서 Node 전역을 실수로 사용해도 컴파일이 통과하거나, 반대로 Vite 설정이 DOM 계약을 물려받을 수 있어. Project reference로 나누면 각 파일이 실제 실행 환경에 맞는 타입만 보게 돼.
For anyone wondering why strict is missing from tsconfig.app.json, this is expected with TypeScript 6.0+. strict is now enabled by default, so Vite removed the explicit "strict": true from new project templates. If you were looking for it and couldn't find it, these references explain the change:
TypeScript 6.0 announcement: https://devblogs.microsoft.com/typescript/announcing-typescript-6-0/#simple-default-changes
Vite PR: https://github.com/vitejs/vite/pull/22110