0Pricing
TypeScript Academy · 课时

构建简单的代码检查工具

使用编译器 API 创建自定义诊断工具

构建简单的代码检查工具 是 CoddyKit 上的免费 TypeScript Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 TypeScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 TypeScript Academy 课程共包含 4 节课。

什么是代码检查工具

代码检查工具会分析源代码,报告风格或正确性问题。使用 TypeScript 编译器接口,您可以构建 ESLint 插件单独无法实现的、具备类型感知能力的规则。

// Goal: warn when console.log is called in TypeScript files

项目设置

创建一个 Node.js 脚本,加载一个 TypeScript program,遍历 AST 并报告诊断信息。

import ts from "typescript";
import path from "path";

const files = ["src/index.ts"];
const program = ts.createProgram(files, { strict: true });

定义规则

一个 rule 是接收 AST 节点的函数;如果违反该 rule,它会返回一条可选的诊断消息。

type Diagnostic = { file: string; line: number; message: string };

function noConsoleLog(node: ts.Node, sf: ts.SourceFile): Diagnostic | null {
  if (!ts.isCallExpression(node)) return null;
  const expr = node.expression.getText(sf);
  if (expr !== "console.log") return null;
  const { line } = sf.getLineAndCharacterOfPosition(node.pos);
  return { file: sf.fileName, line: line + 1, message: "No console.log allowed" };
}

遍历 AST

编写一个递归的 walk,对每个源文件中的每个节点应用所有 rules。

function walk(
  node: ts.Node,
  sf: ts.SourceFile,
  rules: ((n: ts.Node, sf: ts.SourceFile) => Diagnostic | null)[]
): Diagnostic[] {
  const diags: Diagnostic[] = [];
  for (const rule of rules) {
    const d = rule(node, sf);
    if (d) diags.push(d);
  }
  ts.forEachChild(node, child => diags.push(...walk(child, sf, rules)));
  return diags;
}

运行代码检查器

遍历所有源文件,应用 rules,并打印诊断信息。

const rules = [noConsoleLog];
const allDiagnostics: Diagnostic[] = [];

for (const sf of program.getSourceFiles()) {
  if (!sf.isDeclarationFile) {
    allDiagnostics.push(...walk(sf, sf, rules));
  }
}

allDiagnostics.forEach(d =>
  console.log(`${d.file}:${d.line} — ${d.message}`)
);

添加类型感知规则

使用类型检查器构建依赖表达式 TypeScript 类型的 rules。

const checker = program.getTypeChecker();

function noAnyReturn(node: ts.Node, sf: ts.SourceFile): Diagnostic | null {
  if (!ts.isFunctionDeclaration(node)) return null;
  const sig = checker.getSignatureFromDeclaration(node);
  if (!sig) return null;
  const ret = checker.getReturnTypeOfSignature(sig);
  if (ret.flags & ts.TypeFlags.Any) {
    const { line } = sf.getLineAndCharacterOfPosition(node.pos);
    return { file: sf.fileName, line: line + 1, message: "Function returns any" };
  }
  return null;
}

持续集成的退出代码

当发现诊断信息时返回非零退出代码,以便持续集成流水线使构建失败。

if (allDiagnostics.length > 0) {
  console.error(`${allDiagnostics.length} lint error(s)`);
  process.exit(1);
}
process.exit(0);

规则:无未使用变量

编译器接口通过 ts.getPreEmitDiagnostics 提供未使用变量诊断信息,用内置检查增强您的自定义 rules。

const preEmit = ts.getPreEmitDiagnostics(program);
preEmit.forEach(d => {
  const msg = ts.flattenDiagnosticMessageText(d.messageText, "
");
  console.log(msg);
});

规则:要求返回类型

当函数缺少显式返回类型注解时发出警告的规则,有助于强制执行文档规范。

function requireReturnType(node: ts.Node, sf: ts.SourceFile): Diagnostic | null {
  if (!ts.isFunctionDeclaration(node)) return null;
  if (!node.type) {
    const { line } = sf.getLineAndCharacterOfPosition(node.pos);
    return { file: sf.fileName, line: line + 1, message: "Missing return type" };
  }
  return null;
}

与 ESLint 比较

您的自定义代码检查器可以补充 ESLint。使用 ESLint 处理风格规则,使用您的 TypeScript 编译器接口工具处理 ESLint 无法表达的类型感知 rules。

// ESLint: stylistic and common pattern rules
// Compiler API linter: deep type reasoning, custom constraints

回顾:构建代码检查器

TypeScript 编译器接口代码检查器会创建 program,使用 rules 遍历 AST,可选地查询类型检查器,并在出现错误时以非零状态退出。这种方法可以实现真正具备类型感知能力的代码检查 rules。

快速检查

是什么让编译器接口代码检查器比 ESLint 更有优势?

您学到的内容

您使用编译器接口构建了一个简单的 TypeScript 代码检查器:加载 program,遍历 AST,应用 rules(可选类型感知),并报告诊断信息。这是任何 TypeScript 项目进行自定义静态分析的基础。

常见问题解答

「构建简单的代码检查工具」课时是免费的吗?

是的 — 「构建简单的代码检查工具」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 TypeScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 TypeScript Academy 课程共包含 4 节课。

「构建简单的代码检查工具」这节课中我会学到什么?

使用编译器 API 创建自定义诊断工具 你通过在浏览器中直接运行的动手代码来练习 TypeScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 TypeScript Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 TypeScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「构建简单的代码检查工具」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 TypeScript Academy 课中编写并运行代码吗?

能。每节 TypeScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用 API 创建 TypeScript 程序
  2. 使用访问器遍历 AST
  3. 自定义转换器与代码生成
  4. 构建简单的代码检查工具
← 返回 TypeScript Academy