~/web-app-dev.md
WEB_APP_DEV

TypeScript 7 업그레이드는 속도 개선이 아니라 빌드 계약 재점검이다

10분 읽기·2026.07.13·출처 4·00
오늘의 질문

TypeScript 7로 tsc가 빨라졌다면, 우리 웹앱 팀은 무엇을 먼저 검증해야 할까?

web-app-dev.md
TypeScript build contract

TypeScript 7 업그레이드는 속도 개선이 아니라 빌드 계약 재점검이다

1. 왜 지금 봐야 하나

TypeScript 팀은 2026년 7월 8일 TypeScript 7.0을 발표했다. 공식 블로그의 핵심 표현은 강하다. TypeScript 7은 TypeScript의 “10x faster native port”이며, 기존 코드베이스의 구조와 로직을 가능한 한 충실하게 유지하면서 새 네이티브 코드베이스로 옮겼고, full build에서 보통 8~12배 수준의 속도 향상을 기대할 수 있다고 설명한다.

웹앱 개발자에게 이 소식은 단순히 “타입 체크가 빨라졌다”가 아니다. TypeScript는 거의 모든 웹앱 개발 루프에 끼어 있다.

  • 에디터가 빨리 뜨는가?
  • tsc --noEmit이 PR마다 얼마나 걸리는가?
  • Next.js, Vite, Hono, Supabase 타입 생성 코드가 CI에서 안정적으로 검증되는가?
  • AI 코딩 에이전트가 수정 후 타입 오류를 즉시 확인할 수 있는가?
  • 오래된 tsconfig.json 기본값에 기대던 프로젝트가 업그레이드 후 같은 출력 구조를 유지하는가?

TypeScript 7은 이 모든 루프의 시간을 줄일 수 있다. 하지만 속도가 빨라진 도구는 실패도 더 빨리 반복한다. 특히 이번 버전은 네이티브 포트, 병렬화, LSP 기반 에디터 통합, 기본값 변화, 오래된 옵션의 hard error가 함께 온다. 그래서 오늘의 핵심은 “업그레이드하자”가 아니라 업그레이드 전에 우리 프로젝트가 TypeScript에 기대고 있던 빌드 계약을 명시하자다.

오늘의 핵심 문장: TypeScript 7의 성능 개선은 공짜 점수가 아니라, tsconfig, CI, 에디터, 타입 생성물이 같은 계약을 공유하는지 드러내는 압력 테스트다.

2. 핵심 개념

이번 글의 핵심 개념은 **빌드 계약(build contract)**이다.

웹앱 팀에서 TypeScript는 “문법 검사기”처럼 보이지만 실제로는 여러 약속을 동시에 담당한다.

계약질문깨졌을 때 보이는 증상
입력 계약어떤 파일을 프로젝트에 포함할까?테스트 파일, generated file, monorepo 패키지가 갑자기 포함/제외된다
출력 계약컴파일 결과가 어디에 어떤 구조로 나올까?dist/src 구조가 바뀌거나 배포 산출물이 달라진다
전역 타입 계약어떤 @types/*가 자동으로 들어올까?describe, process, Bun, NodeJS 같은 이름이 사라진다
모듈 계약Node, bundler, browser 중 어떤 해석 규칙을 쓸까?path alias, ESM/CJS interop, package exports 해석이 달라진다
병렬화 계약타입 체크와 빌드를 어디까지 동시에 돌릴까?CI 메모리 사용량, 로그 순서, 외부 병렬 빌드와 충돌한다
도구 계약에디터·프레임워크·AI 에이전트가 어떤 tsc를 호출할까?로컬은 통과하지만 CI나 에디터만 다른 오류를 낸다

TypeScript 7의 중요한 변화는 이 계약들을 더 명시적으로 만들게 한다는 점이다. 빠른 native compiler와 LSP는 개발 루프를 줄여 주지만, rootDir, types, 오래된 module/target 옵션 같은 설정은 업그레이드 순간에 “그동안 암묵적으로 기대던 것”을 드러낸다.

3. 최신 이슈와 연결

공식 발표에서 TypeScript 7은 npm install -D typescript로 설치할 수 있고, workspace의 새 tscnpx tsc로 실행한다고 설명한다. npm 메타데이터 확인 결과 typescript 패키지의 latest dist-tag는 7.0.2이고, next는 7.1.0-dev 계열로 이어지고 있었다. 즉 7.0은 별도 preview 패키지에만 머무는 실험이 아니라 표준 typescript 패키지의 stable 흐름에 들어왔다.

또 하나의 큰 변화는 병렬화다. TypeScript 7은 parsing, type-checking, emitting 등 여러 단계를 병렬로 수행한다. 공식 글은 --checkers, --builders 같은 실험적 제어 플래그와, 병렬화를 끄는 --singleThreaded 플래그를 언급한다. 이것은 작은 로컬 프로젝트보다 monorepo, CI, container worker, AI 에이전트가 반복 실행하는 환경에서 중요하다. 이미 Nx, Turborepo, GitHub Actions matrix, Vercel build처럼 외부에서 병렬화를 걸고 있다면 TypeScript 내부 병렬화까지 겹쳐 CPU와 메모리 예산을 다시 봐야 한다.

세 번째 변화는 기본값과 deprecation이다. 공식 글은 rootDir이 이제 ./를 기본으로 하고, 내부 source directory는 명시해야 한다고 설명한다. types는 기본적으로 []가 되며, 예전처럼 모든 global @types를 끌어오려면 ['*']로 되돌릴 수 있다. 또한 target: es5, downlevelIteration, moduleResolution: node/node10, module: amd/umd/systemjs/none, baseUrl 같은 오래된 설정은 더 이상 그냥 넘어가지 않는 hard error 또는 no-op 변경으로 다뤄진다.

이 변화는 최신 프레임워크 팀에게도 현실적인 영향을 준다. Next.js, Vite, Hono, Supabase CLI, GraphQL codegen, 테스트 러너가 만들어 내는 타입 파일은 각자 tsconfig를 읽거나 확장한다. 지금까지는 “우연히 전역 타입이 보였던” 테스트 코드가 TypeScript 7에서 types: [] 기본값 때문에 실패할 수 있다. src 아래만 배포한다고 생각했던 패키지도 rootDir 기본값 변화로 출력 구조가 달라질 수 있다.

마지막으로 TypeScript 7의 native port 이력도 확인할 필요가 있다. microsoft/typescript-go 저장소는 preview 시절 @typescript/native-previewtsgo 명령을 안내했고, 7.0 RC 이후에는 명령 이름이 tsc라고 설명한다. 이제 개발자가 봐야 할 것은 “새 바이너리가 빠른가?”가 아니라 “우리 도구 체인이 어떤 tsc를 실제로 부르는가?”다.

4. 개발자 관점 해석

1) 속도 개선은 코드 리뷰 정책을 바꿀 수 있다

예전에는 tsc --noEmit이 너무 느려서 PR마다 전체 타입 체크를 생략하거나, 변경 패키지만 검사하거나, 에디터 오류를 믿고 넘어가는 팀이 많았다. TypeScript 7이 실제 프로젝트에서 8~12배에 가까운 개선을 보여 준다면 정책을 바꿀 수 있다.

예를 들어 이렇게 말할 수 있다.

zsh — 생존확인.sh
모든 PR은 변경 패키지 테스트와 별도로 root tsc --noEmit을 반드시 통과해야 한다.
AI가 만든 PR은 타입 체크 결과를 PR 설명에 붙인다.

즉 성능 개선은 단순한 체감 속도가 아니라 품질 게이트를 더 자주 실행할 수 있게 하는 조건이다.

2) types 기본값 변화는 테스트와 런타임 경계를 드러낸다

전역 타입은 편하지만 위험하다. Jest를 쓰지 않는 파일에서도 describe가 보이고, Node 런타임이 아닌 브라우저 코드에서도 process가 보이면 코드가 실제 실행 환경보다 넓은 세계를 타입으로 착각한다.

TypeScript 7의 types: [] 기본값은 이 착각을 줄이는 방향이다. 웹앱에서는 오히려 좋은 기회다.

zsh — 생존확인.sh
{
  "compilerOptions": {
    "types": []
  }
}

그리고 환경별로 나눈다.

zsh — 생존확인.sh
// tsconfig.node.json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "types": ["node"]
  }
}
zsh — 생존확인.sh
// tsconfig.test.json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "types": ["node", "vitest/globals"]
  }
}

이렇게 하면 “브라우저 코드”, “서버 코드”, “테스트 코드”가 어떤 전역 이름에 의존하는지 더 명확해진다.

3) rootDir은 배포 산출물의 모양을 정한다

rootDir을 명시하지 않아도 돌아가던 패키지는 업그레이드 때 위험하다. 예를 들어 src/index.tsdist/index.js로 내보내야 하는 라이브러리가 dist/src/index.js처럼 바뀌면 package exports, Docker copy, serverless handler path가 깨질 수 있다.

그래서 TypeScript 7 업그레이드 PR에는 타입 오류뿐 아니라 산출물 구조 diff도 있어야 한다.

zsh — 생존확인.sh
업그레이드 검증:
- npx tsc --showConfig 결과 비교
- dist 파일 tree 비교
- package.json exports가 실제 파일을 가리키는지 확인
- 서버리스 entrypoint path 확인

4) 병렬화는 CI 예산의 일부다

--checkers, --builders, --singleThreaded 같은 옵션은 “고급 사용자용 튜닝”처럼 보이지만 작은 팀도 알아야 한다. GitHub Actions runner 2코어 환경에서 이미 여러 package build를 동시에 돌리고 있다면, 각 package의 tsc가 내부 병렬화를 과하게 쓰면서 오히려 느려지거나 메모리 부족이 날 수 있다.

처음에는 기본값으로 측정하고, 문제가 생길 때만 제어하자. 중요한 것은 감으로 옵션을 바꾸는 것이 아니라 아래 숫자를 남기는 것이다.

  • 로컬 cold run / warm run 시간
  • CI 타입 체크 시간
  • 최대 메모리 사용량
  • 병렬 package 수
  • --singleThreaded 비교 결과

AI 코딩 에이전트를 쓰는 팀이라면 더 중요하다. 에이전트는 작은 수정마다 tsc를 반복 실행한다. 타입 체크가 빨라지는 만큼 “수정 후 타입 체크를 반드시 실행하라”는 완료 조건을 강제하기 쉬워진다.

5. 내 프로젝트에 적용할 체크포인트

TypeScript 7 업그레이드를 검토한다면 아래를 체크하자.

  • 실제 설치 버전: npm view typescript dist-tags와 lockfile의 typescript 버전이 일치하는가?
  • 도구 호출 경로: Next.js, Vite, Vitest, ESLint, codegen, IDE가 같은 workspace typescript를 쓰는가?
  • 설정 출력: npx tsc --showConfig 결과를 업그레이드 전후로 비교했는가?
  • 전역 타입: Node, Vitest/Jest, Bun, Cypress, Playwright 타입을 types에 명시했는가?
  • 소스 루트: rootDir이 배포 산출물 구조를 의도대로 보존하는가?
  • 오래된 옵션: target: es5, moduleResolution: node, baseUrl 같은 deprecation 대상이 남아 있지 않은가?
  • 모듈 해석: 앱은 bundler, Node 서버/CLI는 nodenext처럼 실행 환경에 맞게 나뉘어 있는가?
  • CI 자원: TypeScript 내부 병렬화와 monorepo runner 병렬화가 충돌하지 않는가?
  • 타입 생성물: Supabase 타입, GraphQL codegen, OpenAPI client 생성물이 TypeScript 7에서 같은 오류 상태를 유지하는가?
  • 롤백 경로: lockfile revert만으로 TypeScript 6.x로 돌아갈 수 있는가?

6. 오늘 10분 액션

오늘 바로 전체 업그레이드를 하지 않아도 된다. 대신 “업그레이드 전 스냅샷”을 만든다.

  1. 현재 버전을 확인한다.
zsh — 생존확인.sh
node -p "require('./node_modules/typescript/package.json').version"
npx tsc --version
  1. 현재 설정을 저장한다.
zsh — 생존확인.sh
npx tsc --showConfig > .tmp/tsconfig-before-ts7.json
  1. 현재 타입 체크 시간을 잰다.
zsh — 생존확인.sh
time npx tsc --noEmit
  1. 전역 타입 의존을 찾는다.
zsh — 생존확인.sh
# 예시: 테스트 전역이나 Node 전역을 앱 코드에서 쓰는지 확인
rg "\b(describe|it|expect|process|Buffer|NodeJS)\b" src app server tests
  1. 업그레이드 브랜치에서 TypeScript 7을 설치하고 같은 명령을 반복한다.
zsh — 생존확인.sh
npm install -D typescript@latest
npx tsc --showConfig > .tmp/tsconfig-after-ts7.json
time npx tsc --noEmit
  1. PR 설명에 아래 네 줄을 붙인다.
zsh — 생존확인.sh
TypeScript 7 검증:
- tsc before/after 시간:
- 새로 발생한 오류:
- rootDir/types/moduleResolution 변경 여부:
- CI 메모리/병렬화 관찰:

이 10분 액션의 목표는 “성공적으로 올렸다”가 아니다. 우리 프로젝트가 TypeScript에 어떤 암묵적 약속을 기대고 있었는지 보이게 만드는 것이다.

7. 더 볼 자료

중복 회피 메모

로컬 content/generated와 Supabase 최근 web_app_dev 글을 확인했다. 최근 글은 Next.js 16.3 에이전트 검증 루프, pg_graphql introspection 기본 비활성화, PostgREST 13 JWT kid 검증, Supabase Auth URL 라우팅, Hono 서버리스 어댑터, Turbopack 캐시, Next.js 인증/streaming, Server Actions POST 계약, React Compiler를 다뤘다. 2026-06-12에 “Node가 TypeScript를 바로 실행해도, 웹앱 빌드 계약은 사라지지 않는다”라는 TypeScript 관련 글이 있었지만, 그 글은 Node의 TypeScript 실행과 빌드/런타임 경계를 다뤘다. 이번 글은 TypeScript 7.0의 native compiler, 병렬화, rootDir/types 기본값, deprecation hard error를 바탕으로 웹앱 팀의 업그레이드 전 빌드 계약 점검에 집중한다.

오늘 10분 액션+5%

댓글 0

최신순 ▾
한 줄 남기기

혹시 이 글을 읽는 동료 개발자가 있다면, GitHub으로 로그인하고 한 줄 흔적을 남겨줘요. (스팸 방지용 로그인이에요)