TypeScript(tsconfig.json - references)

在 TypeScript 中,references(项目引用)是用于管理多项目依赖关系 的核心配置,通过 tsconfig.json 中的 references 字段实现。其核心作用是将大型项目拆分为多个独立子项目(如工具库、业务模块、UI 组件库等),支持子项目间的隔离编译、依赖复用,同时提升整体编译效率(仅重新编译修改的子项目)。

使用示例:

json 复制代码
{
  "references": [
    { "path": "../utils/tsconfig.json" } 
  ]
}

一、使用前提

要使用 references,被引用的子项目(依赖项)必须满足以下约束:

  1. 子项目的 tsconfig.json 中需设置 "composite": true(启用复合项目模式,允许被其他项目引用);
  2. 子项目需明确指定 "rootDir"(源代码根目录)和 "outDir"(编译输出目录),确保输出文件结构可被引用方识别;
  3. 建议开启 "declaration": true(生成 .d.ts 类型声明文件),确保引用方能获取类型提示。

二、核心配置字段

1. 引用方配置(references 字段)

在需要依赖其他子项目的「引用方项目」的 tsconfig.json 中,通过 references 数组声明依赖,每个依赖项包含以下属性:

  • path(必填):指向被引用子项目的 tsconfig.json 文件路径(相对路径或绝对路径);
  • prepend(可选,默认 true):若为 true,被引用项目的编译输出会自动添加到引用方的模块查找路径中,无需手动配置 baseUrlpaths

2. 被引用方配置(复合项目约束)

被引用的「子项目」的 tsconfig.json 需包含以下关键配置:

json

json 复制代码
{
  "compilerOptions": {
    "composite": true,        // 启用复合项目,允许被引用
    "rootDir": "./src",       // 源代码根目录(必须明确)
    "outDir": "./dist",       // 编译输出目录(必须明确)
    "declaration": true,      // 生成 .d.ts 类型声明(推荐)
    "declarationMap": true    // 生成类型声明的源映射(可选,便于调试)
  },
  "include": ["./src/**/*"]   // 明确包含的源代码文件
}

三、使用步骤与示例

假设我们有一个大型项目,拆分为 3 个子项目,结构如下:

plaintext

scss 复制代码
my-monorepo/                // 根目录(可包含根 tsconfig.json,也可仅作为文件夹)
├─ packages/
│  ├─ utils/                // 子项目 1:工具库(被依赖项)
│  │  ├─ src/               // utils 源代码
│  │  │  └─ math.ts         // 工具函数(如 add 方法)
│  │  └─ tsconfig.json      // utils 的配置(复合项目)
│  ├─ components/           // 子项目 2:UI 组件库(依赖 utils)
│  │  ├─ src/               // components 源代码
│  │  │  └─ Button.tsx      // UI 组件(使用 utils 的 add 方法)
│  │  └─ tsconfig.json      // components 的配置(引用 utils)
│  └─ app/                  // 子项目 3:主应用(依赖 utils 和 components)
│     ├─ src/               // app 源代码
│     │  └─ index.tsx       // 主应用入口(使用 components 的 Button)
│     └─ tsconfig.json      // app 的配置(引用 utils 和 components)
└─ package.json             // 根项目依赖(可选,用于管理 monorepo 依赖)

步骤 1:配置被引用方(utils 子项目)

packages/utils/tsconfig.json(复合项目配置):

json

json 复制代码
{
  "compilerOptions": {
    "target": "es2015",
    "module": "commonjs",
    "composite": true,        // 启用复合项目
    "rootDir": "./src",       // 源代码根目录
    "outDir": "./dist",       // 编译输出到 dist 目录
    "declaration": true,      // 生成 .d.ts 类型声明
    "strict": true
  },
  "include": ["./src/**/*"],  // 包含所有 src 下的文件
  "exclude": ["node_modules"]
}

packages/utils/src/math.ts 中编写工具函数:

typescript

typescript 复制代码
// 工具函数:加法
export const add = (a: number, b: number): number => a + b;

步骤 2:配置引用方 1(components 子项目,依赖 utils)

packages/components/tsconfig.json(声明对 utils 的引用):

json

json 复制代码
{
  "compilerOptions": {
    "target": "es2015",
    "module": "commonjs",
    "jsx": "react-jsx",       // 假设是 React 组件库
    "rootDir": "./src",
    "outDir": "./dist",
    "declaration": true,
    "strict": true
  },
  "include": ["./src/**/*"],
  "exclude": ["node_modules"],
  // 声明依赖:引用 utils 子项目
  "references": [
    { "path": "../utils/tsconfig.json" }  // 指向 utils 的 tsconfig 路径
  ]
}

packages/components/src/Button.tsx 中使用 utils 的 add 函数:

tsx

typescript 复制代码
// 导入 utils 的 add 函数(无需配置 paths,因 references.prepend 默认 true)
import { add } from "@my-monorepo/utils";  // 假设 utils 在 package.json 中声明为 "@my-monorepo/utils"
// 或相对路径:import { add } from "../utils/dist/src/math";(不推荐,references 会自动处理路径)

interface ButtonProps {
  count: number;
}

export const Button = ({ count }: ButtonProps) => {
  // 使用 utils 的 add 函数
  const handleClick = () => alert(`新计数:${add(count, 1)}`);
  return <button onClick={handleClick}>点击加 1</button>;
};

步骤 3:配置引用方 2(app 主应用,依赖 utils 和 components)

packages/app/tsconfig.json(声明对 utils 和 components 的引用):

json

json 复制代码
{
  "compilerOptions": {
    "target": "es2015",
    "module": "commonjs",
    "jsx": "react-jsx",
    "rootDir": "./src",
    "outDir": "./dist",
    "strict": true
  },
  "include": ["./src/**/*"],
  "exclude": ["node_modules"],
  // 声明多个依赖:utils 和 components
  "references": [
    { "path": "../utils/tsconfig.json" },
    { "path": "../components/tsconfig.json" }
  ]
}

packages/app/src/index.tsx 中使用 components 的 Button 组件:

tsx

javascript 复制代码
import { Button } from "@my-monorepo/components";  // 导入 UI 组件
import React from "react";
import ReactDOM from "react-dom/client";

const root = ReactDOM.createRoot(document.getElementById("root")!);
root.render(
  <React.StrictMode>
    {/* 使用 components 的 Button 组件,传递 count 属性 */}
    <Button count={0} />
  </React.StrictMode>
);

步骤 4:编译与运行

  1. 单独编译子项目 :进入某个子项目目录,执行 tsc 即可编译(如编译 utils:cd packages/utils && tsc);

  2. 编译所有依赖项目 :在引用方项目中执行 tsc --build(缩写 tsc -b),TypeScript 会自动编译所有被引用的子项目(若子项目已编译且无修改,则跳过);

    • 示例:在 app 目录执行 tsc -b,会先检查 utils 和 components 是否最新,若未编译则自动编译,再编译 app;
  3. 运行主应用 :编译完成后,执行 app 的输出文件(如 node packages/app/dist/src/index.js,或根据框架配置启动)。

四、常见场景与注意事项

1. 场景扩展:根项目统一管理

若需要统一编译所有子项目,可在根目录创建 tsconfig.json,通过 references 包含所有子项目,实现「一键编译全部」:

json

json 复制代码
// 根目录 tsconfig.json
{
  "files": [],  // 根项目无源代码,仅用于管理引用
  "references": [
    { "path": "./packages/utils" },
    { "path": "./packages/components" },
    { "path": "./packages/app" }
  ]
}

执行 tsc -b 即可从根目录编译所有子项目。

2. 注意事项

  • 避免循环引用:不可出现 A 引用 B、B 引用 A 的循环依赖,会导致编译错误;

  • 路径正确性references.path 必须指向被引用项目的 tsconfig.json 文件(而非文件夹,若指向文件夹,TypeScript 会自动查找其中的 tsconfig.json);

  • composite 必开启 :被引用项目若未设置 "composite": true,引用方会报错;

  • 类型声明依赖 :若被引用项目未开启 "declaration": true,引用方可能无法获取类型提示(仅能运行,但失去 TypeScript 类型检查能力)。

通过 references,可将大型项目拆分为高内聚、低耦合的子模块,不仅提升编译效率,还便于团队协作(不同团队维护不同子项目),是 TypeScript 大型应用的最佳实践之一。

相关推荐
还是大剑师兰特15 小时前
TypeScript 面试题及详细答案 100题 (91-100)-- 工程实践与框架集成
前端·javascript·typescript·1024程序员节
fruge1 天前
TypeScript 基础类型与接口详解
javascript·ubuntu·typescript
海鸥两三2 天前
Uni-App(Vue3 + TypeScript)项目结构详解 ------ 以 Lighting-UniApp 为例,提供源代码
vue.js·typescript·uni-app·1024程序员节
菜鸟una3 天前
【微信小程序 + 消息订阅 + 授权】 微信小程序实现消息订阅流程介绍,代码示例(仅前端)
前端·vue.js·微信小程序·小程序·typescript·taro·1024程序员节
前端初见3 天前
快速上手TypeScript,TS速通
javascript·ubuntu·typescript
郑板桥303 天前
TypeScript:npm的types、typings、@type的区别
javascript·typescript·npm
Java陈序员3 天前
免费高颜值!一款跨平台桌面端视频资源播放器!
vue.js·typescript·electron
菜鸟una4 天前
【瀑布流大全】分析原理及实现方式(微信小程序和网页都适用)
前端·css·vue.js·微信小程序·小程序·typescript
还是大剑师兰特4 天前
TypeScript 面试题及详细答案 100题 (71-80)-- 模块与命名空间
前端·javascript·typescript
一点七加一4 天前
Harmony鸿蒙开发0基础入门到精通Day01--JavaScript篇
开发语言·javascript·华为·typescript·ecmascript·harmonyos