microsoft / microsoft/TypeScript

Improve support for internal packages by resolving path aliases

Đang mở
#58,657 4 bình luận 15 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Awaiting More Feedback Suggestion
Ngôn ngữ chính
Go
Star
111k
Fork
14.4k
Merge trung bình
1 ngày 19 giờ
Pull request đã merge (30 ngày)
117

Mô tả

🔍 Search Terms

Internal packages
Path alias
Resolve paths

✅ Viability Checklist
⭐ Suggestion

Add a tsconfig.json to the exports field in package.json so that internal packages can share their TypeScript config especially their path aliases.

// ./libs/math/package.json
{
  "name": "@repo/libs-math",
  "version": "1.0.0",
  "private": true,
  "main": "./src/index.ts",
  "types": "./src/index.ts",
  "exports": {
    // exports local tsconfig.json so consumers can resolve local path aliases
    "./tsconfig.json": "./tsconfig.json",
    ".": {
      "import": "./src/index.ts",
      "require": "./src/index.ts",
      "types": "./src/index.ts"
    }
  }
}
📃 Motivating Example

Please find a reproduction example here: https://github.com/zirkelc/typescript-internal-packages

Install all dependencies with pnpm install in the project root. Then open apps/foo/src/index.ts and you will see that TypeScript cannot resolve the dependency to @repo/libs-with-alias correctly.


I'm using internal packages to share code in my monorepo. An internal package is package which is NOT published to NPM and which is NOT explicitly compiled with TypeScript before it can be used by other packages. It exports the source TypeScript *.ts files from the package.json via the main, types, and exports fields:

// ./libs/math
{
  "name": "@repo/libs-math",
  "private": true,
  "main": "./src/index.ts",
  "types": "./src/index.ts",
  "exports": {
    ".": {
      "import": "./src/index.ts",
      "require": "./src/index.ts",
      "types": "./src/index.ts"
    }
  }
}
// ./libs/math/src/index.ts
export const add = (a: number, b: number) => {
	return a + b;
};

This internal package is meant to be installed by other packages in the same repo:

// ./apps/foo
{
  "name": "@repo/apps-foo",
  "dependencies": {
    "@repo/libs-math": "workspace:*"
  }
}

And can be used like a normal dependency which resolve to the original uncompiled TypeScript code:

// ./apps/foo/src/index.ts
import { add } from '@repo/libs-math'
//              ^?  Imports the typescript code from the internal package

Everything good so far. This pattern works well as long as none of the internal packages is using TypeScript path aliases. However, let's re-structure the internal package and use path aliases like ~/math:

// ./libs/math/tsconfig.json
{
  "extends": "@tsconfig/node20/tsconfig.json",
  "compilerOptions": {
    "paths": {
      "~/math": ["./src/math/index.ts"],
    },
  },
  "include": [ "src"]
}

The path alias ~/math points to the sub-folder ./src/math/index.ts. The previous ./src/index.ts becomes a simple barrel file exports

// ./libs/math/src/index.ts
export * from '~/math'
// ^? Exports from local path alias pointing to ./libs/math/src/math/index.ts

Now, the internal package @repo/libs-math uses path aliases which are defined its own local tsconfig.json. However, the previous import in ./apps/foo will now start to fail:

// ./apps/foo/src/index.ts
import { add } from '@repo/libs-math'
//               ^? Module '"@repo/libs-math"' has no exported member 'add'

TypeScript doesn't find the function anymore, even though go to definition to @repo/libs-math still works.

I assume the reason is the following: TypeScript resolves the imports starting from the app ./apps/foo/src/index.ts to the internal package ./libs/math/src/index.ts. However, TypeScript still works inside the ./apps/foo/tsconfig.json and is not aware of the path aliases defined by the ./libs/math/tsconfig.json. It would need a way to recognize it is in a different package now and must look for the right tsconfig.json in ./libs/math.

That's where my idea of exporting the tsconfig.json in the package.json comes in. TypeScript would notice it is working in a different package when it was moving from ./apps/foo/src/index.ts to ./libs/math/src/index.ts. Then it sees this new package has a local TypeScript config exported from the local ./libs/math/package.json. It sees the path aliases and applies these aliases for all paths inside ./libs/math/*.

💻 Use Cases

There are two possible workarounds:

  1. global path alias: create a root-level tsconfig.paths.json which defines all path aliases for the entire project. Each package-level tsconfig.json extends from this config. There are two disadvantages to this workaround:
  • packages cannot define package-level path aliases as they would overwrite the inherited root-level aliases
  • each package can import from every other package via path aliases. that means you could accidentally import from the internal package @repo/libs-math via a typescript path alias instead of a node package (workspace) import.
  1. project references: typescript project references can solve this issue, but they add a lot of complexity due intermediate build steps and overhead in extra multiple tsconfig.json. The package @repo/apps-foo has a node dependency to @repo/libs-math via package.json. For project references, this dependency must be replicated again in the tsconfig.json via references. So the dependency graph of package.json must be repeated for every new internal package.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu bằng việc tái hiện trong typescript-internal-packages: chạy pnpm install, sau đó kiểm tra apps/foo/src/index.ts, libs/math/package.json và libs/math/tsconfig.json. Theo dõi cách các export của package nội bộ và các alias đường dẫn cục bộ được phân giải. Được xem là hoàn tất khi import từ @repo/libs-math phân giải add một cách chính xác mà không cần alias toàn cục hoặc tham chiếu dự án.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
typescript
Lĩnh vực
compilers
Loại issue
Tính năng
Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức độ hoạt động
Sôi nổi
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
35/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.