← 中文资源

简体中文版本

TSConfig 路径别名与模块解析

配置 TypeScript 路径别名替代深层相对导入:编译器按 baseUrl 与 paths 映射,运行时为每个目标注册对应解析器。

阅读英文原文

示例说明

相对导入的层级每深一层,可读性与可重构性就差一分:移动一个文件要改一路的点点点。路径别名把内部模块的入口收敛为稳定标识,依赖关系从文件位置解耦。配置分两半:tsconfig 的 paths 负责类型检查与编辑器提示,打包器或运行时的 alias 注册负责实际解析,两边必须同步维护。

技术要点

  • baseUrl 与 paths 共同定义别名映射
  • 运行时需配套注册等价解析规则
  • 别名导入让模块边界显式可见

代码解读

paths 把 at 前缀的三组别名映射到源码树:features 与 shared 用通配捕获子路径,config 直指单一入口。orders 服务里的导入语句即别名的消费形态;注释中的 esbuild 命令展示打包侧如何注册同样的映射关系。

使用建议

别名数量克制在边界级而不是每目录一个。tsconfig 修改要连带检查测试与打包配置的三方一致。公共别名建议 lint 规则强制,防止新旧风格混存。

代码示例

// tsconfig.json 局部:
{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "@/features/*": ["features/*"],
      "@/shared/*": ["shared/*"],
      "@/config": ["config/index.ts"]
    }
  }
}

// src/config/index.ts —— 显式环境分层
export const config = {
  port: Number(process.env.PORT ?? 3000),
  logLevel: process.env.LOG_LEVEL ?? 'info',
} as const;

// src/features/orders/service.ts —— 别名导入取代 ../../../
import { config } from '@/config';
import { logger } from '@/shared/logger';

export async function listOrders(page: number) {
  logger.debug('listing orders page', page, 'port', config.port);
  return [{ id: 1, total: 42 }];
}

// 打包器(如 esbuild)注册解析器:
// esbuild src/index.ts --bundle //   --alias:@/features=./src/features //   --alias:@/shared=./src/shared //   --alias:@/config=./src/config/index.ts

const orders = await listOrders(1);
console.log('orders:', orders.length);