Skip to Content
WebTypeScriptTypeScript 중급18. 최종 점검과 다음 과목 예고

이번 편의 결과물: npm run verify가 타입 테스트를 포함해 전부 통과하고, API 클라이언트·폼 스키마·유틸 타입 라이브러리가 갖춰진 expense-tracker 최종본을 브라우저에서 시연합니다. · 다루는 개념: npm run verify 전체 실행, 기능 체크리스트, 다음 과목 예고

01편에서 점검했던 typescript_fundamentals 종료 상태의 expense-tracker에, 17편까지 조건부 타입부터 zod 통합 API 클라이언트까지 쌓아 올렸습니다. 이 편에서는 새 코드를 추가하지 않고, 지금까지 만든 것이 하나의 명령으로 전부 검증되는지 확인한 뒤 결과물을 시연합니다.

이 편에서 만드는 파일

expense-tracker/ └── package.json ~ (verify 스크립트에 test:types 단계 추가)

개념 정리

verify에 타입 테스트 추가하기

typescript_fundamentals 18편에서 만든 verify 스크립트는 typecheck·test·build 세 단계였습니다. 16편에서 추가한 test:types(vitest --typecheck)는 지금까지 verify에 포함되지 않아, 유틸 타입이 깨져도 verify가 통과할 수 있는 빈틈이 있었습니다. 이 편에서 그 빈틈을 막습니다.

// package.json (발췌) { "scripts": { "typecheck": "tsc --noEmit", "test:types": "vitest --typecheck --run", "test": "vitest run", "build": "vite build", "verify": "npm run typecheck && npm run test:types && npm run test && npm run build" } }

typecheck(전체 프로젝트 타입 검사) 다음에 test:types(유틸 타입 회귀 검사)를 두어, 가장 가벼운 검사부터 순서대로 실패를 드러냅니다. test(런타임 동작 검사)와 build(번들 생성)는 그 뒤를 잇습니다.

실습

1. verify 스크립트 갱신

package.json을 위 내용대로 고칩니다.

2. 전체 검증 실행

npm run verify
> tsc --noEmit (오류 없음) > vitest --typecheck --run ✓ src/lib/types/utility.test-d.ts (6) ✓ src/lib/types/brand.test-d.ts (5) ✓ src/lib/types/pipe.test-d.ts (2) Type Test Files 3 passed (3) > vitest run ✓ tests/createTransaction.test.ts (1) ✓ tests/storage.test.ts (2) ✓ tests/stats.test.ts (3) ✓ tests/apiClient.test.ts (4) ✓ tests/transactionForm.test.ts (3) > vite build ✓ built in 431ms

3. 기능 체크리스트로 브라우저 시연

npm run preview

아래 항목을 브라우저에서 하나씩 확인합니다.

  • 거래 추가 폼에 잘못된 금액(음수)이나 빈 메모를 입력하면, TransactionFormSchema(14편)가 만든 에러 메시지가 필드 옆에 표시된다.
  • 거래를 추가·수정·삭제하면 네트워크 탭에 MSW가 가로챈 /api/transactions 요청과 응답이 찍힌다(15편).
  • 응답 데이터의 idTransactionId 브랜디드 타입(07편)이라, 이 값을 카테고리 자리에 잘못 넣는 코드는 편집기에서 바로 오류로 표시된다.
  • 예산 규칙 설정 화면에서 기본값은 DeepReadonly(06편)로 고정되어 있고, 부분 수정 폼은 DeepPartial(06편)로 일부 필드만 받는다.
  • 통계 패널의 groupBy 결과 타입이 UnwrapPromise·ElementOf(03편)로 정확히 좁혀져, 존재하지 않는 프로퍼티에 접근하면 컴파일 오류가 난다.
  • 개발자 도구 콘솔에서 apiClient.request('GET', '/transactions')apiClient.request('POST', '/transactions', body)(09편 오버로드)를 각각 호출하면 반환 타입이 서로 다르게 추론된다.

4. lib/types 최종 트리와 유틸 요약

lib/types/에 실제로 남는 파일은 다음 네 개입니다. 각 파일의 완전한 코드는 이미 03·05·06·07·11·17편에서 작성했으므로 여기서는 다시 싣지 않습니다.

expense-tracker/src/lib/types/ ├── index.ts (17, 배럴) ├── utility.ts (03, 05, 06, 17) ├── brand.ts (07, 17) ├── pipe.ts (11, 17) ├── utility.test-d.ts (16) ├── brand.test-d.ts (16) └── pipe.test-d.ts (16)
유틸소속 파일한 줄 설명
UnwrapPromise<T>utility.ts중첩된 Promise를 재귀적으로 벗겨 내부 값 타입을 반환
ElementOf<T>utility.ts배열·읽기 전용 배열 타입에서 요소 타입을 추출
FormErrors<T>utility.ts각 필드 키에 Error 접미사를 붙인 선택적 에러 메시지 맵으로 리매핑
JsonValueutility.ts문자열·숫자·불리언·null과 중첩 배열·객체를 포괄하는 JSON 재귀 유니온
DeepPartial<T>utility.ts중첩 객체의 모든 단계를 선택적 프로퍼티로 전환
DeepReadonly<T>utility.ts중첩 객체의 모든 단계를 readonly로 전환
Brand<T, B>brand.ts원시 타입에 문자열 태그를 붙여 구조가 같아도 섞이지 않게 하는 브랜드 헬퍼
TransactionIdbrand.ts거래 식별자 전용 브랜디드 문자열 타입
CategoryIdbrand.ts카테고리 식별자 전용 브랜디드 문자열 타입
pipe(value, ...fns)pipe.ts가변 튜플로 단계별 입출력 타입을 이어 맞추는 함수 합성 유틸

직접 해보기

  1. package.jsonverify 순서를 buildtest:types보다 앞에 오도록 바꾼 뒤, lib/types/utility.tsUnwrapPromise 정의를 의도적으로 깨뜨려 verify가 어디서 멈추는지 비교해 보세요.
  2. 위 기능 체크리스트 중 하나를 골라, 어떤 편에서 그 동작이 만들어졌는지 목차를 보지 않고 코드만 보고 추적해 보세요.

정답 보기

순서를 바꾸면 UnwrapPromise가 깨진 상태에서도 build(번들링)는 타입을 검사하지 않으므로 먼저 성공하고, 그 다음 test:types 단계에서야 실패가 드러납니다. 실패를 가장 빠르게 알고 싶다면 가벼운 검사(typecheck, test:types)를 무거운 검사(build)보다 앞에 두는 편이 낫습니다.

자주 하는 실수

증상원인고치는 법
verify는 통과했는데 배포 후 유틸 타입 관련 버그 발견test:types 단계를 verify에 포함하지 않음verify 스크립트에 test:types를 반드시 넣는다
MSW 네트워크 로그가 안 보임npm run preview는 프로덕션 번들을 서빙할 뿐, MSW 서비스 워커 등록 코드가 프로덕션 빌드에서 빠져 있음브라우저 시연은 npm run dev(MSW 활성화)에서 하고, preview는 번들 결과 확인용으로 구분한다
체크리스트 항목이 어떤 편 코드인지 못 찾음배럴·리팩터링(17편) 이후 파일 위치가 바뀜lib/types/index.ts에서 시작해 각 export의 선언부까지 따라간다

확인 문제

문제 14지선다
이번 편에서 verify 스크립트에 test:types 단계를 추가한 이유는
문제 24지선다
verify에서 typecheck·test:types를 build보다 앞에 두는 이유는
문제 34지선다
TransactionId 브랜디드 타입이 이번 과목 전체에서 실질적으로 막아주는 문제는
문제 44지선다
다음 과목 typescript_3에서 다루는 내용으로 예고된 것은

참고 자료

Last updated on