TypeScript 5.7의 Path Rewriting으로 모노레포 타입 참조 개선하기

문제 상황

회사 프로젝트가 터보레포 기반 모노레포로 전환되면서 패키지 간 타입 참조에서 문제가 발생했다. @company/ui 패키지를 @company/web에서 import할 때 타입은 정상 인식되지만, 빌드 후 생성된 .d.ts 파일의 경로가 꼬이는 현상이었다.

// packages/web/src/index.ts
import { Button } from '@company/ui';

// 빌드 후 packages/web/dist/index.d.ts
import { Button } from '../../../ui/src/Button'; // 상대경로로 변환됨

패키지를 npm에 배포하면 이 상대경로가 깨져서 타입 추론이 불가능했다.

TypeScript 5.7 해결책

TypeScript 5.7에서 추가된 --rewriteRelativeImportExtensions 옵션과 개선된 path mapping 로직을 활용했다.

// packages/ui/tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@company/ui": ["./src/index.ts"]
    },
    "declaration": true,
    "declarationMap": true
  }
}

핵심은 각 패키지의 package.json에서 exports 필드를 명확히 정의하는 것이었다.

{
  "name": "@company/ui",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js"
    }
  }
}

결과

빌드 후 생성된 타입 파일이 패키지명 기반으로 import를 유지하게 되었다.

// packages/web/dist/index.d.ts
import { Button } from '@company/ui'; // 패키지명 유지

모노레포 내부에서도, npm 배포 후에도 타입 추론이 정상 작동한다. TypeScript 5.6까지는 복잡한 빌드 스크립트로 우회했었는데 이제는 설정만으로 해결됐다.

추가로 verbatimModuleSyntax 옵션도 함께 적용해서 불필요한 type-only import가 런타임에 남지 않도록 정리했다.