设计思想

发布于 2026-07-26

index.ts 作用

index.ts 是 TypeScript 的入口文件,用于定义项目的入口点。

index.ts

把一个目录变成一个模块(Module),作为这个目录的统一入口(Entry)。 例如如下的目录结构:

cheatsheets
├── views
│   ├── CheatsheetArticleView.tsx
│   └── CheatsheetsIndexView.tsx
├── lib
│   └── data-utils.ts
├── types
│   └── CheatsheetItem.ts
├── components
│   ├── CheatsheetBlocks.tsx
│   ├── ReadingProgress.tsx
│   ├── ArticlePager.tsx
│   ├── CheatSheetToc.tsx
│   └── CheatsheetTopicPage.tsx
└── index.ts

整个 cheatsheets 就是一个可以对外导出的模块,在 index.ts 中导出所有需要对外暴露的文件。

// src/cheatsheets/index.ts
 
export * from "./views/CheatsheetArticleView";
export * from "./views/CheatsheetsIndexView";
export * from "./lib/data-utils";
export * from "./types/CheatsheetItem";
export * from "./components/CheatsheetBlocks";
export * from "./components/ReadingProgress";
export * from "./components/ArticlePager";
export * from "./components/CheatSheetToc";
export * from "./components/CheatsheetTopicPage";

就可以通过如下的方式引用:

import {
    CheatsheetArticleView,
    CheatsheetsIndexView,
    dataUtils,
    CheatsheetItem,
    CheatsheetBlocks,
    ReadingProgress,
    ArticlePager,
    CheatSheetToc,
    CheatsheetTopicPage,
} from "@/cheatsheets";

而不是像这样直接引用文件:

import { CheatsheetArticleView } from '@/src/cheatsheets/views/CheatsheetArticleView';

从这个最基础的使用场景来看,index.ts 更像是某个目录的大门(Public API)。

注意

在模块内部使用了相对路径 ./来引用文件,而在模块外部使用 @ 或 别名引用。

// views/CheatsheetArticleView.tsx
 
import { getArticle } from "../lib/data-utils";
import type { CheatsheetItem } from "../types/CheatsheetItem";

使用相对路径即可,因为它们属于同一个模块。

为什么叫 index.ts?

Node.js 继承自以前 CommonJS 的约定。例如:

foo/
    index.js

那么:

require("./foo")
 
// 实际上等价于:
 
require("./foo/index.js")

ESM 时代虽然没有强制要求,但这个约定一直保留了下来。

收益和理解

  • 如上面的示例,没有 index.ts 时,调用方需要知道 cheatsheets 目录的结构,才能正确引用其中的文件。而有了 index.ts 后,调用方只需要知道 cheatsheets 目录的名称,就可以正确引用其中的文件。
  • 如果目录结构调整,只需要调整 index.ts 中的导出,不需要调整调用方的代码。
  • 这就是:隐藏实现(Implementation Hiding)也叫Facade(门面模式)。
  • 通常大型项目中,每一级都会有 index.ts 来隐藏目录结构。

加深理解

  • 目录的入口(Entry Point)
  • 目录的公共 API(Public API)
  • 目录的门面(Facade)
  • 隐藏内部实现的边界(Module Boundary)

一个目录真正对外承诺提供什么能力,不是由目录里有哪些文件决定,而是由 index.ts 决定。

什么时候应该写 index.ts?

  1. 一个目录需要对外暴露
  2. 一个组件目录
  3. 一个 SDK

资源类的目录不需要,没有模块的概念。