daily-bible 모듈에 TypeScript strict 모드 타입
목차
daily-bible 모듈의 서버 응답 처리 부분에서 TypeScript strict 모드 빌드를 통과하기 위해 res.json() 반환값의 타입을 명시적으로 캐스팅했다.
strict 모드가 요구하는 타입 엄격함
팀에서 TypeScript strict 모드를 적용한 지 한참 되었는데, 이건 단순한 린팅 규칙이 아니라 런타임 에러를 사전에 차단하는 보험이다. 특히 서버와의 통신 부분은 그 중요성이 더 크다.
res.json()은 서버에서 돌아오는 응답 본문을 파싱하는 메서드인데, TypeScript 입장에선 그 결과의 구체적인 타입을 알 수 없다. 따라서 unknown으로 반환된다. strict 모드 이전에는 any로 취급하거나 암묵적으로 무시했을 법한 부분인데, strict 모드에서는 "이 unknown 값을 너가 명시적으로 안전하게 다루고 있는가?"를 강제한다.
unknown이 vs any의 차이
| 구분 | any | unknown |
|---|---|---|
| 타입 검사 | 무시 | 필수 |
| 프로퍼티 접근 | 자유 | 타입 좁혀야 함 |
| 함수 호출 | 자유 | 타입 좁혀야 함 |
| 보안성 | 낮음 | 높음 |
any를 써버리면 "나중에 누군가 이 코드를 잘못 건드릴 때" 타입 체커가 아무 도움이 못 된다. unknown은 개발자에게 "니가 지금 뭘 받는 거고, 그걸 어떻게 쓸 건데?"를 명시적으로 구현하라고 강요한다. 이게 처음엔 번거로워 보이지만, 6개월 뒤 코드를 다시 읽을 때는 이 명시성이 얼마나 큰 자산인지 느껴진다.
API 응답 처리의 실무 패턴
일반적으로 서버 응답을 다룰 땐 이런 식으로 타입을 좁혀간다:
// ❌ 피하기
const data = await res.json(); // unknown
data.userId; // Error: unknown에는 userId가 없을 수도 있음
// ✅ 타입 가드 활용
const data = await res.json();
if (typeof data === 'object' && data !== null && 'userId' in data) {
const userId = (data as { userId: string }).userId; // 이제 안전
}
// ✅ 스키마 검증 (더 강력)
const schema = z.object({ userId: z.string() });
const data = await res.json().then(d => schema.parse(d)); // 런타임 검증
실무에선 보통 zod, valibot 같은 스키마 라이브러리를 통해 서버 응답을 런타임에 검증하면서 동시에 타입을 확정 짓는다. 이 방식이 가장 안전한데, 애초에 서버가 보낸 형식과 클라이언트가 기대하는 형식의 괴리를 캐치할 수 있기 때문이다.
팀 차원의 타입 안전성과 배운 점
strict 모드 빌드를 필수로 두면서 느낀 가장 큰 효과는 PR 리뷰 때 타입 관련 이슈가 줄어들었다는 것이다. 예전엔 "이 값이 null일 수도 있지 않나?" 같은 코멘트가 왕왕 있었는데, 이제는 "빌드가 안 되니까" 애초에 그런 상황이 원천 차단된다.
또한 이런 변경이 누적되면서 코드베이스 전체의 신뢰도가 올라간다. 신입이 들어와서 기존 코드를 읽을 때도 "이 값이 undefined일 수 있나?" 같은 의문 없이 타입 정의를 믿고 진행할 수 있다.
다만 팀에서 strict 모드를 강제할 때는 점진적 마이그레이션이 중요했다. 처음부터 전체 코드를 strict로 돌리려고 했다면 저항이 심했을 텐데, 모듈 단위로 천천히 적용하면서 "아, 이게 왜 필요한데?"를 각자 깨닫게 했다. 이 fix도 그 과정의 일부고, 앞으로도 비슷한 작은 개선들이 계속 쌓여갈 거 같다.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.