Babel TypeScript 类型完全参考

本文档专门面向 TypeScript 使用者,覆盖 Babel 工具链所有包的完整类型定义,重点解决"对象很多、没有类型提示很费心神"的问题。 配合 技巧步骤/Babel AST入门 阅读,后者侧重基本用法和实战示例,本文侧重 TypeScript 类型系统。 1. 安装与 TypeScript 配置(#%E5%AE%89%E8%A3%85%E4%B8%8E-typescript-%E9%85%8D%E7%BD%AE) 2. @babel/parser 类型详解(#babelparser-%E7%B1%BB%E5%9E%8B%E8%AF%A6%E8%A7

分享

官方文档:https://babeljs.io/docs/babel-types
适用版本:@babel/types 7.x+(2026-05-08 核实)

本文档专门面向 TypeScript 使用者,覆盖 Babel 工具链所有包的完整类型定义,重点解决"对象很多、没有类型提示很费心神"的问题。

配合 技巧步骤/Babel AST入门 阅读,后者侧重基本用法和实战示例,本文侧重 TypeScript 类型系统。


目录

  1. 安装与 TypeScript 配置
  2. @babel/parser 类型详解
  3. @babel/types 节点类型详解
  4. @babel/traverse 类型详解
  5. @babel/generator 类型详解
  6. @babel/core 类型详解
  7. TypeScript 使用模式

安装与 TypeScript 配置

安装命令

# 运行时依赖
npm install @babel/parser @babel/traverse @babel/types @babel/generator @babel/core

# TypeScript 类型声明
# @babel/parser、@babel/types、@babel/core 自带类型,无需单独安装
npm install --save-dev @types/babel__traverse @types/babel__generator

各包类型来源汇总

类型声明位置 说明
@babel/parser 包内自带 node_modules/@babel/parser/typings/babel-parser.d.ts
@babel/types 包内自带 自动生成,最完整
@babel/core 包内自带 node_modules/@babel/core/lib/index.d.ts
@babel/traverse DefinitelyTyped @types/babel__traverse
@babel/generator DefinitelyTyped @types/babel__generator

tsconfig.json 推荐配置

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "skipLibCheck": false
  }
}

esModuleInterop: true 是关键,因为 @babel/traverse@babel/generatorexport default 导出,但实际是 CommonJS 模块,没有这个选项 import traverse from 会报错。

推荐的 import 方式

// @babel/parser —— 具名导入
import { parse, parseExpression } from "@babel/parser";

// @babel/types —— 命名空间导入(对象很多,用 * as t 最方便)
import * as t from "@babel/types";

// @babel/traverse —— 默认导入(需要 esModuleInterop)
import traverse from "@babel/traverse";

// @babel/generator —— 默认导入
import generate from "@babel/generator";

// @babel/core —— 具名导入
import { transformSync, parseSync } from "@babel/core";

@babel/parser 类型详解

函数签名

import { parse, parseExpression } from "@babel/parser";

// 解析完整程序,返回 File 节点(根节点)
function parse(code: string, options?: ParserOptions): t.File;

// 解析单个表达式,返回 Expression 节点
function parseExpression(code: string, options?: ParserOptions): t.Expression;

ParserOptions 接口(完整字段)

interface ParserOptions {
  // ---- 语法模式 ----

  // 模块类型
  // "script"      : 默认,普通脚本,不支持 import/export
  // "module"      : ES 模块,支持 import/export
  // "commonjs"    : CommonJS(允许顶层 return、new.target、资源声明)
  // "unambiguous" : 自动检测(有 import/export 则为 module,否则为 script)
  sourceType?: "script" | "commonjs" | "module" | "unambiguous";

  // 强制严格模式(默认 false)
  strictMode?: boolean;

  // 启用语法插件(见下方插件列表)
  plugins?: ParserPlugin[];

  // ---- 容错与恢复 ----

  // 遇到语法错误时继续解析,而非抛出异常(处理混淆代码时建议开启)
  errorRecovery?: boolean;

  // ---- 位置信息 ----

  // 源文件名,会附加到位置信息中
  sourceFilename?: string;

  // 起始行号(默认 1)
  startLine?: number;

  // 起始列号(默认 0)
  startColumn?: number;

  // 起始字符索引(默认 0)
  startIndex?: number;

  // 每个节点附加 [start, end] 位置数组(默认 false)
  ranges?: boolean;

  // ---- 节点控制 ----

  // 把 token 列表附加到 AST 的 tokens 字段(默认 false)
  tokens?: boolean;

  // 是否将注释挂载到相邻节点(默认 true)
  attachComment?: boolean;

  // 把 (expr) 括号表达式包装成 ParenthesizedExpression 节点(默认 false)
  createParenthesizedExpressions?: boolean;

  // 把 import() 解析为 ImportExpression 而非 CallExpression(默认 true)
  createImportExpressions?: boolean;

  // ---- 特殊权限 ----

  // 允许在任意位置使用 import/export(默认 false)
  allowImportExportEverywhere?: boolean;

  // 允许在函数外使用 await(默认 false)
  allowAwaitOutsideFunction?: boolean;

  // 允许在函数外使用 yield(默认 false)
  allowYieldOutsideFunction?: boolean;

  // 允许在函数外使用 new.target(默认 false)
  allowNewTargetOutsideFunction?: boolean;

  // 允许在函数外使用 return(默认 false)
  allowReturnOutsideFunction?: boolean;

  // 允许在非方法中使用 super(默认 false)
  allowSuperOutsideMethod?: boolean;

  // 允许未声明的 export(默认 false)
  allowUndeclaredExports?: boolean;

  // 是否遵循 Annex B(传统 JS 兼容性规则,默认 true)
  annexB?: boolean;
}

plugins 可选值

plugins 字段接受 ParserPlugin[],每个元素可以是字符串,也可以是 [插件名, 选项对象] 的元组。

type ParserPlugin =
  // 语言扩展
  | "flow"
  | "flowComments"
  | "jsx"
  | "typescript"
  | "v8intrinsic"

  // 实验性 ECMAScript 提案
  | "asyncDoExpressions"
  | "decimal"
  | "decorators"                    // 需要配合选项:["decorators", { version: "2023-11", decoratorsBeforeExport: true }]
  | "decorators-legacy"
  | "decoratorAutoAccessors"
  | "deferredImportEvaluation"
  | "deprecatedImportAssert"
  | "destructuringPrivate"
  | "discardBinding"
  | "doExpressions"
  | "explicitResourceManagement"    // using / await using
  | "exportDefaultFrom"
  | "functionBind"
  | "functionSent"
  | "importReflection"
  | "moduleBlocks"
  | "optionalChainingAssign"
  | "partialApplication"
  | "pipelineOperator"              // 需要配合选项:["pipelineOperator", { proposal: "minimal" }]
  | "recordAndTuple"
  | "sourcePhaseImports"
  | "throwExpressions"

  // ESTree 兼容输出(供 ESLint 使用)
  | "estree"

  // 以下默认已启用
  | "asyncGenerators"
  | "bigInt"
  | "classProperties"
  | "classPrivateProperties"
  | "classPrivateMethods"
  | "classStaticBlock"
  | "dynamicImport"
  | "exportNamespaceFrom"
  | "logicalAssignment"
  | "nullishCoalescingOperator"
  | "numericSeparator"
  | "objectRestSpread"
  | "optionalCatchBinding"
  | "optionalChaining"
  | "privateIn"
  | "regexpUnicodeSets"
  | "topLevelAwait"
  | "importAttributes";

带类型的常用示例

import { parse, parseExpression } from "@babel/parser";
import * as t from "@babel/types";

// 返回类型明确为 t.File
const ast: t.File = parse(`const x = 1`, {
  sourceType: "module",
  plugins: ["typescript"],
  errorRecovery: true,
});

// Program 是 ast.program,包含所有顶层语句
const program: t.Program = ast.program;

// parseExpression 返回 t.Expression(联合类型,需要收窄)
const expr: t.Expression = parseExpression(`a + b`);
if (t.isBinaryExpression(expr)) {
  // 这里 expr 被收窄为 t.BinaryExpression
  console.log(expr.operator); // string,类型安全
}

@babel/types 节点类型详解

BaseNode 基础接口

所有 AST 节点都继承 BaseNode

interface BaseNode {
  type: string;
  start?: number | null;      // 起始字符偏移
  end?: number | null;        // 结束字符偏移
  loc?: SourceLocation | null; // 行列位置信息
  leadingComments?: Comment[];
  innerComments?: Comment[];
  trailingComments?: Comment[];
  extra?: Record<string, unknown> | null;
}

interface SourceLocation {
  start: Position;
  end: Position;
  filename: string;
  identifierName?: string | null;
}

interface Position {
  line: number;   // 1-based
  column: number; // 0-based
  index: number;  // 字符偏移,0-based
}

核心节点 TypeScript 接口定义

顶层节点

interface File extends BaseNode {
  type: "File";
  program: Program;
  comments?: (CommentBlock | CommentLine)[] | null;
  tokens?: any[] | null;
}

interface Program extends BaseNode {
  type: "Program";
  body: Statement[];
  directives: Directive[];            // "use strict" 等指令
  sourceType: "script" | "module";
  interpreter?: InterpreterDirective | null; // #!/usr/bin/env node
}

标识符与字面量

interface Identifier extends BaseNode {
  type: "Identifier";
  name: string;
  // 以下字段在 TypeScript/Flow 语法中出现
  optional?: boolean | null;
  typeAnnotation?: TypeAnnotation | TSTypeAnnotation | null;
  decorators?: Decorator[] | null;
}

interface StringLiteral extends BaseNode {
  type: "StringLiteral";
  value: string;
}

interface NumericLiteral extends BaseNode {
  type: "NumericLiteral";
  value: number;
}

interface BooleanLiteral extends BaseNode {
  type: "BooleanLiteral";
  value: boolean;
}

interface NullLiteral extends BaseNode {
  type: "NullLiteral";
}

interface BigIntLiteral extends BaseNode {
  type: "BigIntLiteral";
  value: string; // 注意:是字符串,不是 bigint
}

interface RegExpLiteral extends BaseNode {
  type: "RegExpLiteral";
  pattern: string;
  flags: string;
}

// 模板字符串:`hello ${name}`
interface TemplateLiteral extends BaseNode {
  type: "TemplateLiteral";
  quasis: TemplateElement[];       // 静态文本片段(n+1 个)
  expressions: (Expression | TSType)[]; // 动态插值(n 个)
}

// 模板字符串的静态片段
interface TemplateElement extends BaseNode {
  type: "TemplateElement";
  value: {
    raw: string;    // 原始文本(含转义符,如 \n)
    cooked: string | null; // 解析后文本(null 表示含非法转义)
  };
  tail: boolean; // 是否是最后一个片段
}

表达式节点

// obj.prop(computed=false)或 obj[expr](computed=true)
// 注意:MemberExpression 是联合类型
type MemberExpression = MemberExpressionComputed | MemberExpressionNonComputed;

interface MemberExpressionNonComputed extends BaseNode {
  type: "MemberExpression";
  object: Expression | Super;
  property: Identifier | PrivateName;
  computed: false;
  optional?: boolean | null;
}

interface MemberExpressionComputed extends BaseNode {
  type: "MemberExpression";
  object: Expression | Super;
  property: Expression;
  computed: true;
  optional?: boolean | null;
}

// fn(a, b)
interface CallExpression extends BaseNode {
  type: "CallExpression";
  callee: Expression | Super | V8IntrinsicIdentifier;
  arguments: (Expression | SpreadElement | ArgumentPlaceholder)[];
  optional?: boolean | null;
  typeArguments?: TypeParameterInstantiation | TSTypeParameterInstantiation | null;
}

// a + b, a === b, a in b 等
interface BinaryExpression extends BaseNode {
  type: "BinaryExpression";
  operator:
    | "+" | "-" | "/" | "%" | "*" | "**"
    | "&" | "|" | ">>" | ">>>" | "<<" | "^"
    | "==" | "===" | "!=" | "!=="
    | "in" | "instanceof"
    | ">" | "<" | ">=" | "<="
    | "|>";
  left: Expression | PrivateName;
  right: Expression;
}

// x = 1, a += b 等
interface AssignmentExpression extends BaseNode {
  type: "AssignmentExpression";
  operator:
    | "=" | "+=" | "-=" | "/=" | "%=" | "*=" | "**="
    | "&=" | "|=" | ">>=" | ">>>=" | "<<=" | "^="
    | "||=" | "&&=" | "??=";
  left:
    | Identifier | MemberExpression | OptionalMemberExpression
    | ArrayPattern | ObjectPattern
    | TSAsExpression | TSSatisfiesExpression | TSTypeAssertion | TSNonNullExpression;
  right: Expression;
}

// { a: 1, b: 2 }
interface ObjectExpression extends BaseNode {
  type: "ObjectExpression";
  properties: (ObjectMethod | ObjectProperty | SpreadElement)[];
}

// 对象属性(也是联合类型)
type ObjectProperty = ObjectPropertyComputed | ObjectPropertyNonComputed;

interface ObjectPropertyNonComputed extends BaseNode {
  type: "ObjectProperty";
  key: Identifier | StringLiteral | NumericLiteral | BigIntLiteral | PrivateName;
  value: Expression | PatternLike;
  computed: false;
  shorthand: boolean;   // 是否是简写形式:{ a } 而非 { a: a }
  decorators?: Decorator[] | null;
}

interface ObjectPropertyComputed extends BaseNode {
  type: "ObjectProperty";
  key: Expression;
  value: Expression | PatternLike;
  computed: true;
  shorthand: boolean;
  decorators?: Decorator[] | null;
}

// [1, 2, 3]
interface ArrayExpression extends BaseNode {
  type: "ArrayExpression";
  elements: (null | Expression | SpreadElement)[]; // null 表示空位:[1,,3]
}

函数节点

// function foo(a, b) { ... }
interface FunctionDeclaration extends BaseNode {
  type: "FunctionDeclaration";
  id: Identifier | null;        // 匿名函数声明时为 null(export default function)
  params: FunctionParameter[];
  body: BlockStatement;
  generator: boolean;           // function*
  async: boolean;               // async function
  declare?: boolean | null;     // TypeScript: declare function
  returnType?: TypeAnnotation | TSTypeAnnotation | null;
  typeParameters?: TypeParameterDeclaration | TSTypeParameterDeclaration | null;
  predicate?: FlowPredicate | null;
}

// const fn = function(a, b) { ... }
interface FunctionExpression extends BaseNode {
  type: "FunctionExpression";
  id?: Identifier | null;       // 具名函数表达式:const fn = function foo() {}
  params: FunctionParameter[];
  body: BlockStatement;
  generator: boolean;
  async: boolean;
  returnType?: TypeAnnotation | TSTypeAnnotation | null;
  typeParameters?: TypeParameterDeclaration | TSTypeParameterDeclaration | null;
  predicate?: FlowPredicate | null;
}

// (a, b) => a + b  或  (a) => { return a }
interface ArrowFunctionExpression extends BaseNode {
  type: "ArrowFunctionExpression";
  params: FunctionParameter[];
  body: BlockStatement | Expression; // 表达式体时为 Expression,有花括号时为 BlockStatement
  async: boolean;
  expression: boolean;    // body 是 Expression(非 BlockStatement)时为 true
  generator?: boolean | null;  // 箭头函数不能是 generator,此字段为 null/false
  returnType?: TypeAnnotation | TSTypeAnnotation | null;
  typeParameters?: TypeParameterDeclaration | TSTypeParameterDeclaration | null;
  predicate?: FlowPredicate | null;
}

// FunctionParameter 是参数类型的联合
type FunctionParameter =
  | Identifier
  | Pattern              // 解构参数
  | RestElement          // ...rest
  | TSParameterProperty; // TypeScript: public/private/readonly 参数

声明节点

// var/let/const/using/await using x = 1
interface VariableDeclaration extends BaseNode {
  type: "VariableDeclaration";
  kind: "var" | "let" | "const" | "using" | "await using";
  declarations: VariableDeclarator[];
  declare?: boolean | null; // TypeScript: declare const x: string
}

// x = 1(VariableDeclaration 中的单个声明项)
interface VariableDeclarator extends BaseNode {
  type: "VariableDeclarator";
  id: Identifier | ArrayPattern | ObjectPattern | VoidPattern;
  init?: Expression | null;  // null 表示 let x 没有初始值
  definite?: boolean | null; // TypeScript: let x!: string
}

语句节点

// { ... }
interface BlockStatement extends BaseNode {
  type: "BlockStatement";
  body: Statement[];
  directives: Directive[]; // "use strict" 等
}

// 将表达式作为语句:foo()、a = 1 等
interface ExpressionStatement extends BaseNode {
  type: "ExpressionStatement";
  expression: Expression;
}

// return x
interface ReturnStatement extends BaseNode {
  type: "ReturnStatement";
  argument?: Expression | null; // return; 时为 null
}

// if (test) consequent else alternate
interface IfStatement extends BaseNode {
  type: "IfStatement";
  test: Expression;
  consequent: Statement;
  alternate?: Statement | null; // 无 else 时为 null
}

// throw err
interface ThrowStatement extends BaseNode {
  type: "ThrowStatement";
  argument: Expression;
}

// try { ... } catch (e) { ... } finally { ... }
interface TryStatement extends BaseNode {
  type: "TryStatement";
  block: BlockStatement;
  handler?: CatchClause | null;
  finalizer?: BlockStatement | null;
}

// while (test) body
interface WhileStatement extends BaseNode {
  type: "WhileStatement";
  test: Expression;
  body: Statement;
}

// for (init; test; update) body
interface ForStatement extends BaseNode {
  type: "ForStatement";
  init?: VariableDeclaration | Expression | null;
  test?: Expression | null;
  update?: Expression | null;
  body: Statement;
}

模块节点

// import { a, b as c } from 'mod'
// import DefaultExport from 'mod'
// import * as ns from 'mod'
interface ImportDeclaration extends BaseNode {
  type: "ImportDeclaration";
  specifiers: (ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier)[];
  source: StringLiteral;
  attributes?: ImportAttribute[] | null; // import ... with { type: "json" }
  importKind?: "type" | "typeof" | "value" | null; // Flow/TypeScript: import type
  phase?: "source" | "defer" | null; // import.source / import.defer 提案
  module?: boolean | null;
}

// { a } 或 { a as b }
interface ImportSpecifier extends BaseNode {
  type: "ImportSpecifier";
  local: Identifier;
  imported: Identifier | StringLiteral;
  importKind?: "type" | "typeof" | "value" | null;
}

// DefaultExport(import 中的默认导入)
interface ImportDefaultSpecifier extends BaseNode {
  type: "ImportDefaultSpecifier";
  local: Identifier;
}

// * as ns
interface ImportNamespaceSpecifier extends BaseNode {
  type: "ImportNamespaceSpecifier";
  local: Identifier;
}

// export { a, b as c }
// export const x = 1
// export { a } from 'mod'
interface ExportNamedDeclaration extends BaseNode {
  type: "ExportNamedDeclaration";
  declaration?: Declaration | null;          // export const x = 1 时有值
  specifiers: (ExportSpecifier | ExportDefaultSpecifier | ExportNamespaceSpecifier)[];
  source?: StringLiteral | null;             // export ... from 'mod' 时有值
  attributes?: ImportAttribute[] | null;
  exportKind?: "type" | "value" | null;      // export type { Foo }
}

// export default foo
interface ExportDefaultDeclaration extends BaseNode {
  type: "ExportDefaultDeclaration";
  declaration: Declaration | Expression;
  exportKind?: "value" | null;
}

// export * from 'mod'
interface ExportAllDeclaration extends BaseNode {
  type: "ExportAllDeclaration";
  source: StringLiteral;
  exported?: Identifier | StringLiteral | null; // export * as ns from 'mod'
  attributes?: ImportAttribute[] | null;
  exportKind?: "type" | "value" | null;
}

节点别名(类型联合)

@babel/types 定义了大量别名,在 visitor 中可以用别名一次匹配多种节点:

// 主要别名(可直接在 traverse visitor 中使用)
type Expression =
  | Identifier | StringLiteral | NumericLiteral | BooleanLiteral | NullLiteral
  | TemplateLiteral | MemberExpression | CallExpression | NewExpression
  | BinaryExpression | UnaryExpression | LogicalExpression | AssignmentExpression
  | ConditionalExpression | SequenceExpression | ArrowFunctionExpression
  | FunctionExpression | ObjectExpression | ArrayExpression
  | TaggedTemplateExpression | YieldExpression | AwaitExpression
  | /* ... 更多 */;

type Statement =
  | ExpressionStatement | BlockStatement | ReturnStatement | IfStatement
  | VariableDeclaration | FunctionDeclaration | ClassDeclaration
  | ForStatement | ForInStatement | ForOfStatement | WhileStatement
  | DoWhileStatement | SwitchStatement | TryStatement | ThrowStatement
  | BreakStatement | ContinueStatement | LabeledStatement
  | ImportDeclaration | ExportNamedDeclaration | ExportDefaultDeclaration
  | ExportAllDeclaration | /* ... 更多 */;

type Declaration =
  | FunctionDeclaration | ClassDeclaration | VariableDeclaration
  | ExportNamedDeclaration | ExportDefaultDeclaration | ExportAllDeclaration
  | ImportDeclaration | /* ... 更多 */;

type Pattern =
  | AssignmentPattern | ArrayPattern | ObjectPattern | RestElement;

type Node =
  | Expression | Statement | Declaration | Pattern
  | File | Program | TemplateElement | SpreadElement | ObjectProperty
  | ObjectMethod | ClassBody | ClassMethod | ClassProperty
  | /* ... 所有节点的联合类型 */;

类型守卫函数(isXxx)

每个节点类型都有对应的类型守卫函数,调用后 TypeScript 会自动收窄类型

import * as t from "@babel/types";

// 基本签名:
// t.isXxx(node: object | null | undefined, opts?: object): node is Xxx

// opts 是可选的属性过滤器,所有字段都要匹配才返回 true
t.isIdentifier(node)                      // node is t.Identifier
t.isIdentifier(node, { name: "foo" })     // name === "foo" 时才匹配
t.isStringLiteral(node)                   // node is t.StringLiteral
t.isNumericLiteral(node)
t.isBooleanLiteral(node)
t.isNullLiteral(node)
t.isTemplateLiteral(node)
t.isMemberExpression(node)
t.isCallExpression(node)
t.isBinaryExpression(node)
t.isBinaryExpression(node, { operator: "+" })  // 只匹配 + 运算
t.isAssignmentExpression(node)
t.isObjectExpression(node)
t.isObjectProperty(node)
t.isArrayExpression(node)
t.isFunctionDeclaration(node)
t.isFunctionExpression(node)
t.isArrowFunctionExpression(node)
t.isVariableDeclaration(node)
t.isVariableDeclarator(node)
t.isBlockStatement(node)
t.isExpressionStatement(node)
t.isReturnStatement(node)
t.isIfStatement(node)
t.isImportDeclaration(node)
t.isExportNamedDeclaration(node)

// 别名守卫(匹配整个类别)
t.isExpression(node)    // node is t.Expression
t.isStatement(node)     // node is t.Statement
t.isDeclaration(node)   // node is t.Declaration
t.isLiteral(node)       // 匹配所有字面量类型
t.isScope(node)         // 有作用域的节点
t.isFunction(node)      // 所有函数形式
t.isClass(node)         // 所有 class 形式

断言函数(assertXxx)

assertXxxisXxx 的区别:不匹配时抛出 TypeError 而非返回 false。
适合在你确定类型正确但 TypeScript 无法推断的场合做强制收窄。

// 基本签名:
// t.assertXxx(node: object | null | undefined, opts?: object): asserts node is Xxx

t.assertIdentifier(node);               // 断言后 node 类型为 t.Identifier
t.assertCallExpression(node);
t.assertFunctionDeclaration(node);

// 实际使用示例
function processCallee(node: t.Node) {
  t.assertMemberExpression(node);
  // 这里 node 已被收窄为 t.MemberExpression
  console.log(node.object, node.property);
}

构建器函数(完整签名)

import * as t from "@babel/types";

// ---- 字面量 ----
t.identifier(name: string): t.Identifier
t.stringLiteral(value: string): t.StringLiteral
t.numericLiteral(value: number): t.NumericLiteral
t.booleanLiteral(value: boolean): t.BooleanLiteral
t.nullLiteral(): t.NullLiteral
t.bigIntLiteral(value: string): t.BigIntLiteral
t.regExpLiteral(pattern: string, flags?: string): t.RegExpLiteral

// templateLiteral 的 quasis 比 expressions 多一个
t.templateLiteral(
  quasis: t.TemplateElement[],
  expressions: (t.Expression | t.TSType)[]
): t.TemplateLiteral

t.templateElement(
  value: { raw: string; cooked?: string | null },
  tail?: boolean  // 默认 false,最后一个片段需要传 true
): t.TemplateElement

// ---- 表达式 ----
t.memberExpression(
  object: t.Expression | t.Super,
  property: t.Expression | t.Identifier | t.PrivateName,
  computed?: boolean,  // 默认 false
  optional?: boolean | null
): t.MemberExpression

t.callExpression(
  callee: t.Expression | t.Super | t.V8IntrinsicIdentifier,
  args: (t.Expression | t.SpreadElement | t.ArgumentPlaceholder)[],
  typeArguments?: t.TypeParameterInstantiation | t.TSTypeParameterInstantiation | null
): t.CallExpression

t.binaryExpression(
  operator: "+" | "-" | "/" | "%" | "*" | "**" | "&" | "|" | ">>" | ">>>"
    | "<<" | "^" | "==" | "===" | "!=" | "!==" | "in" | "instanceof"
    | ">" | "<" | ">=" | "<=" | "|>",
  left: t.Expression | t.PrivateName,
  right: t.Expression
): t.BinaryExpression

t.assignmentExpression(
  operator: "=" | "+=" | "-=" | "/=" | "%=" | "*=" | "**="
    | "&=" | "|=" | ">>=" | ">>>=" | "<<=" | "^="
    | "||=" | "&&=" | "??=",
  left: t.LVal,
  right: t.Expression
): t.AssignmentExpression

t.objectExpression(
  properties: (t.ObjectMethod | t.ObjectProperty | t.SpreadElement)[]
): t.ObjectExpression

t.objectProperty(
  key: t.Expression | t.Identifier | t.StringLiteral | t.NumericLiteral | t.PrivateName,
  value: t.Expression | t.PatternLike,
  computed?: boolean,   // 默认 false
  shorthand?: boolean,  // 默认 false
  decorators?: t.Decorator[] | null
): t.ObjectProperty

t.objectMethod(
  kind: "method" | "get" | "set",
  key: t.Expression | t.Identifier | t.StringLiteral | t.NumericLiteral | t.PrivateName,
  params: t.FunctionParameter[],
  body: t.BlockStatement,
  computed?: boolean,
  generator?: boolean,
  async?: boolean
): t.ObjectMethod

t.arrayExpression(
  elements?: (null | t.Expression | t.SpreadElement)[]
): t.ArrayExpression

t.spreadElement(argument: t.Expression): t.SpreadElement

// ---- 函数 ----
t.functionDeclaration(
  id: t.Identifier | null,
  params: t.FunctionParameter[],
  body: t.BlockStatement,
  generator?: boolean,  // 默认 false
  async?: boolean       // 默认 false
): t.FunctionDeclaration

t.functionExpression(
  id: t.Identifier | null | undefined,
  params: t.FunctionParameter[],
  body: t.BlockStatement,
  generator?: boolean,
  async?: boolean
): t.FunctionExpression

t.arrowFunctionExpression(
  params: t.FunctionParameter[],
  body: t.BlockStatement | t.Expression,
  async?: boolean  // 默认 false
): t.ArrowFunctionExpression

// ---- 语句 ----
t.blockStatement(
  body: t.Statement[],
  directives?: t.Directive[]
): t.BlockStatement

t.expressionStatement(expression: t.Expression): t.ExpressionStatement
t.returnStatement(argument?: t.Expression | null): t.ReturnStatement

t.ifStatement(
  test: t.Expression,
  consequent: t.Statement,
  alternate?: t.Statement | null
): t.IfStatement

t.throwStatement(argument: t.Expression): t.ThrowStatement
t.tryStatement(
  block: t.BlockStatement,
  handler?: t.CatchClause | null,
  finalizer?: t.BlockStatement | null
): t.TryStatement

// ---- 声明 ----
t.variableDeclaration(
  kind: "var" | "let" | "const" | "using" | "await using",
  declarations: t.VariableDeclarator[]
): t.VariableDeclaration

t.variableDeclarator(
  id: t.LVal,
  init?: t.Expression | null
): t.VariableDeclarator

// ---- 模块 ----
t.importDeclaration(
  specifiers: (t.ImportSpecifier | t.ImportDefaultSpecifier | t.ImportNamespaceSpecifier)[],
  source: t.StringLiteral,
  attributes?: t.ImportAttribute[] | null
): t.ImportDeclaration

t.importSpecifier(
  local: t.Identifier,
  imported: t.Identifier | t.StringLiteral,
  importKind?: "type" | "typeof" | "value" | null
): t.ImportSpecifier

t.importDefaultSpecifier(local: t.Identifier): t.ImportDefaultSpecifier
t.importNamespaceSpecifier(local: t.Identifier): t.ImportNamespaceSpecifier

t.exportNamedDeclaration(
  declaration?: t.Declaration | null,
  specifiers?: (t.ExportSpecifier | t.ExportDefaultSpecifier | t.ExportNamespaceSpecifier)[],
  source?: t.StringLiteral | null,
  attributes?: t.ImportAttribute[] | null
): t.ExportNamedDeclaration

t.exportSpecifier(
  local: t.Identifier,
  exported: t.Identifier | t.StringLiteral
): t.ExportSpecifier

t.exportDefaultDeclaration(
  declaration: t.Declaration | t.Expression
): t.ExportDefaultDeclaration

节点工具函数

// 深度克隆节点(包含所有子节点)
// withoutLocations: true 时去掉位置信息(默认 false)
t.cloneNode<T extends t.Node>(node: T, deep?: boolean, withoutLocations?: boolean): T

// 浅克隆(只克隆顶层,子节点共享引用)
t.shallowEqual(actual: object, expected: object): boolean

// 递归清除节点的位置信息、注释等元数据
// opts.preserveComments: 保留注释(默认 false)
t.removePropertiesDeep(node: t.Node, opts?: { preserveComments?: boolean }): t.Node

// 移除单个节点的位置/注释等非核心属性
t.removeProperties(node: t.Node, opts?: { preserveComments?: boolean }): void

// 判断节点是否表示纯值(无副作用)
t.isPureish(node: t.Node): boolean

// 获取节点的所有 binding 标识符
t.getBindingIdentifiers(node: t.Node, duplicates?: boolean, outerOnly?: boolean): { [name: string]: t.Identifier | t.Identifier[] }

// 判断两个节点是否相等(深度比较)
t.isNodesEquivalent(a: t.Node, b: t.Node): boolean

// 判断节点是否是引用(而非赋值目标)
t.isReferenced(node: t.Node, parent: t.Node, grandparent?: t.Node): boolean

// 获取节点的 type 字段,考虑别名
t.toComputedKey(node: t.ObjectMethod | t.ObjectProperty | t.ClassMethod | t.ClassProperty): t.Expression

@babel/traverse 类型详解

traverse() 函数签名

import traverse from "@babel/traverse";
import * as t from "@babel/types";

// 无 state 时(最常用形式)
function traverse(
  parent: t.Node,
  opts?: TraverseOptions,
  scope?: Scope,
  state?: any,
  parentPath?: NodePath
): void;

// 有 state 时(泛型形式,state 类型安全)
function traverse<S>(
  parent: t.Node,
  opts: TraverseOptions<S>,
  scope: Scope | undefined,
  state: S,
  parentPath?: NodePath
): void;

TraverseOptions / Visitor 接口

// Visitor 是 TraverseOptions 的核心
// 键是节点类型字符串,值是访问函数或 { enter, exit } 对象
type Visitor<S = unknown> =
  // 每个节点类型名都可以作为键
  & { [N in t.Node as N["type"]]?: VisitNode<S, N> }
  // 别名也可以作为键(Function、Expression、Statement 等)
  & { [K in keyof t.Aliases]?: VisitNode<S, t.Aliases[K]> }
  // 多类型用 | 合并:'StringLiteral|NumericLiteral'
  & { [k: `${string}|${string}`]: VisitNode<S, t.Node> }
  // 入口/出口处理
  & VisitNodeObject<S, t.Node>;

// 访问节点可以是函数或对象
type VisitNode<S, P extends t.Node> =
  | VisitNodeFunction<S, P>
  | VisitNodeObject<S, P>;

// 函数形式
type VisitNodeFunction<S, P extends t.Node> =
  (this: S, path: NodePath<P>, state: S) => void;

// 对象形式(enter/exit)
interface VisitNodeObject<S, P extends t.Node> {
  enter?: VisitNodeFunction<S, P>;
  exit?: VisitNodeFunction<S, P>;
}

NodePath<T> 接口(完整字段)

NodePath<T> 是对节点的包装,T 是具体的节点类型(默认为 t.Node)。

interface NodePath<T extends t.Node = t.Node> {
  // ---- 核心属性 ----
  node: T;                      // 当前 AST 节点
  type: T["type"] | undefined;  // 节点类型字符串
  parent: t.Node;               // 父节点(AST 节点,非 path)
  parentPath: NodePath | null;  // 父节点的 path(根节点时为 null)
  scope: Scope;                 // 当前作用域

  // ---- 位置信息 ----
  key: string | number | null;  // 本节点在父节点中的字段名(如 "body"、"left"、0)
  listKey: string | null;       // 本节点所在的数组字段名(如 "body"),非数组时为 null
  inList: boolean;              // 本节点是否在数组中

  // ---- 容器信息 ----
  container: t.Node | t.Node[] | null; // 包含本节点的容器(数组或父节点字段)
  hub: Hub;                     // 全局上下文

  // ---- 状态标记 ----
  removed: boolean;   // 是否已被 remove()
  replaced: boolean;  // 是否已被 replaceWith()
  skipped: boolean;   // 是否已被 skip()

  // ---- 用户数据 ----
  data: Record<string | symbol, unknown>; // 可自由附加数据(如标记"已处理")
  state: any; // traverse 传入的 state

  // ---- 辅助 ----
  contexts: TraversalContext[];
}

NodePath 上的方法

类型判断方法

// path.isXxx(opts?) 的形式对所有节点类型都有
// 返回 boolean,同时收窄 path 的泛型类型
path.isIdentifier(opts?: { name?: string }): this is NodePath<t.Identifier>
path.isStringLiteral(opts?: { value?: string }): this is NodePath<t.StringLiteral>
path.isCallExpression(): this is NodePath<t.CallExpression>
path.isMemberExpression(): this is NodePath<t.MemberExpression>
path.isFunctionDeclaration(): this is NodePath<t.FunctionDeclaration>
path.isExpression(): this is NodePath<t.Expression>
path.isStatement(): this is NodePath<t.Statement>
// ... 200+ 个 isXxx 方法,与 t.isXxx 一一对应

替换节点

// 用单个节点替换当前节点
path.replaceWith(node: t.Node | NodePath): void

// 用多个节点替换(当前节点必须在语句列表中)
path.replaceWithMultiple(nodes: t.Node[]): NodePath[]

// 用代码字符串替换(内部会解析代码)
path.replaceWithSourceString(replacement: string): void

// 将表达式替换为语句序列,返回包裹函数的调用表达式
path.replaceExpressionWithStatements(nodes: t.Statement[]): t.Node

插入节点

// 在当前节点之前插入(当前节点必须在语句列表中)
path.insertBefore(nodes: t.Node | t.Node[]): NodePath[]

// 在当前节点之后插入
path.insertAfter(nodes: t.Node | t.Node[]): NodePath[]

删除节点

path.remove(): void

控制遍历

// 跳过当前节点的所有子节点(本节点仍处理,但不再向下遍历)
path.skip(): void

// 立即停止整个 traverse 遍历
path.stop(): void

// 对当前节点的子节点发起遍历(手动递归)
path.traverse(opts: TraverseOptions, state?: any): void

查找父节点

// 向上查找满足条件的祖先 path(包含当前节点)
// 回调返回 true 时停止,返回该 path
path.find(callback: (path: NodePath) => boolean): NodePath | null

// 向上查找满足条件的祖先 path(不包含当前节点)
path.findParent(callback: (path: NodePath) => boolean): NodePath | null

// 向上找最近的函数作用域的 path
path.getFunctionParent(): NodePath<t.Function> | null

// 向上找最近的语句 path
path.getStatementParent(): NodePath<t.Statement> | null

// 获取从根到当前节点的所有祖先 path(不含当前)
path.getAncestry(): NodePath[]

// 判断某个 path 是否是当前 path 的祖先
path.isAncestor(maybeDescendant: NodePath): boolean

// 判断某个 path 是否是当前 path 的后代
path.isDescendant(maybeAncestor: NodePath): boolean

获取子路径

// 获取某个字段的子 path
// key 是字段名,listKey 是数组下标
path.get(key: string): NodePath | NodePath[]
path.get(key: string, context?: boolean): NodePath<t.Node> | NodePath<t.Node>[]

// 示例
const bodyPaths = path.get("body") as NodePath[];
const firstArg = path.get("arguments.0") as NodePath;

求值

// 静态求值:尝试计算节点的常量值
// confident=true 时才可信,否则 value 无意义
path.evaluate(): { confident: boolean; value: any; deopt?: NodePath }

// 只返回布尔值的求值(用于条件判断)
path.evaluateTruthy(): boolean | undefined

模式匹配

// 判断 MemberExpression 是否匹配指定模式
// 如:path.matchesPattern("console.log")
path.matchesPattern(pattern: string, allowPartial?: boolean): boolean

Binding 相关

// 获取当前节点中所有 binding 的 Identifier 节点
path.getBindingIdentifiers(duplicates?: boolean): { [name: string]: t.Identifier | t.Identifier[] }

// 获取外层 binding 的 Identifier(解构时有区别)
path.getOuterBindingIdentifiers(duplicates?: boolean): { [name: string]: t.Identifier }

// 获取所有 binding 的 NodePath
path.getBindingIdentifierPaths(duplicates?: boolean, outerOnly?: boolean): { [name: string]: NodePath<t.Identifier> }

Scope 接口

interface Scope {
  // ---- 基础属性 ----
  uid: number;          // 作用域唯一 ID
  path: NodePath;       // 产生此作用域的节点 path
  block: t.Node;        // 产生此作用域的节点(与 path.node 相同)
  parent: Scope;        // 父作用域
  hub: Hub;

  // ---- 绑定信息 ----
  // 当前作用域内所有变量绑定(键为变量名)
  bindings: { [name: string]: Binding };

  // 当前作用域内所有变量引用(只有键,值为 true)
  references: { [name: string]: true };

  // ---- 查询方法 ----

  // 获取变量绑定(向上查找父作用域)
  getBinding(name: string): Binding | undefined;

  // 获取仅在当前作用域的绑定(不查父作用域)
  getOwnBinding(name: string): Binding | undefined;

  // 判断变量是否在当前或父作用域中有绑定
  hasBinding(name: string, opts?: { noGlobals?: boolean; noUids?: boolean }): boolean;

  // 判断变量是否仅在当前作用域绑定
  hasOwnBinding(name: string): boolean;

  // 判断变量是否被引用(有使用者)
  hasReference(name: string): boolean;

  // ---- 重命名 ----

  // 重命名变量(自动处理所有引用点,包括声明和使用)
  rename(oldName: string, newName?: string, block?: t.Node): void;

  // ---- 生成新标识符 ----

  // 生成一个当前作用域内唯一的 uid(字符串)
  generateUid(name?: string): string;

  // 生成唯一 uid 并返回 Identifier 节点
  generateUidIdentifier(name?: string): t.Identifier;

  // 基于某个节点名称生成唯一 uid
  generateUidIdentifierBasedOnNode(node: t.Node, defaultName?: string): t.Identifier;

  // ---- 作用域操作 ----

  // 在当前作用域发起遍历
  traverse(node: t.Node, opts: TraverseOptions, state?: any): void;

  // 将引用推送到根作用域(提升变量)
  push(opts: {
    id: t.LVal;
    init?: t.Expression | null;
    unique?: boolean;
    kind?: "var" | "let" | "const";
  }): void;

  // 删除当前作用域的绑定信息(强制重新爬取)
  removeBinding(name: string): void;

  // 重新爬取当前作用域的绑定信息
  crawl(): void;

  // 判断标识符是否是静态的(可以安全求值)
  isStatic(node: t.Node): boolean;

  // 获取所有绑定(包括父作用域)
  getAllBindings(): { [name: string]: Binding };

  // 获取所有绑定名称(包括父作用域)
  getAllBindingNames(): string[];
}

Binding 类

Binding 表示一个变量的绑定信息,通过 scope.getBinding(name)scope.bindings[name] 获取:

type BindingKind =
  | "var"           // var 声明
  | "let"           // let 声明
  | "const"         // const 声明
  | "module"        // import 声明
  | "hoisted"       // function 声明(提升)
  | "param"         // 函数参数
  | "local"         // 函数表达式的 id(如 const fn = function foo() {} 中的 foo)
  | "unknown";      // 无法确定

class Binding {
  identifier: t.Identifier;      // 绑定的 Identifier 节点
  scope: Scope;                  // 绑定所在的作用域
  path: NodePath;                // 声明处的 path
  kind: BindingKind;

  referenced: boolean;           // 是否被引用过
  references: number;            // 被引用次数
  referencePaths: NodePath[];    // 所有引用处的 path

  constant: boolean;             // 是否是常量(没有赋值操作)
  constantViolations: NodePath[]; // 所有对该变量赋值的 path

  // 标记一次引用
  reference(path: NodePath): void;
  // 取消一次引用
  dereference(): void;
  // 标记一次赋值
  reassign(path: NodePath): void;
}

@babel/generator 类型详解

generate() 函数签名

import generate from "@babel/generator";
import * as t from "@babel/types";

// ast 可以是任意 Node,不只是 File
// code 是原始代码(用于 source map)
// 如果是多文件场景,code 可以是文件名到代码内容的映射
function generate(
  ast: t.Node,
  opts?: GeneratorOptions,
  code?: string | { [filename: string]: string }
): GeneratorResult;

GeneratorOptions 接口(所有字段)

interface GeneratorOptions {
  // ---- 注释控制 ----

  // 在注入代码之前添加的注释(如块级帮助函数)
  auxiliaryCommentBefore?: string;

  // 在注入代码之后添加的注释
  auxiliaryCommentAfter?: string;

  // 是否输出注释(默认 true)
  comments?: boolean;

  // 自定义注释过滤器(返回 true 时输出该注释)
  shouldPrintComment?: (comment: string) => boolean;

  // ---- 格式控制 ----

  // 是否紧凑模式(去掉大部分空格)
  // true: 强制紧凑;false: 强制非紧凑;"auto": 跟随 minified 选项
  compact?: boolean | "auto";

  // 是否适度减少空格(比 compact 弱,默认 false)
  concise?: boolean;

  // 是否完全压缩(同时开启 compact,默认 false)
  minified?: boolean;

  // 尝试保留原始行号(可能影响代码可读性,默认 false)
  retainLines?: boolean;

  // 保留函数调用的括号(防止某些压缩工具误删,默认 false)
  retainFunctionParens?: boolean;

  // ---- 字符串/特殊语法 ----

  // 关联的文件名(影响 source map 的 file 字段)
  filename?: string;

  // 是否将字符串输出为 JSON 兼容格式(全部用 Unicode 转义,默认 false)
  jsonCompatibleStrings?: boolean;

  // jsesc 库的选项(控制字符串转义行为)
  // 常用选项:{ minimal: true } 只转义必须转义的字符
  jsescOption?: {
    quotes?: "single" | "double" | "backtick";
    minimal?: boolean;
    numbers?: "decimal" | "hexadecimal" | "octal" | "binary";
    indent?: string;
    indentLevel?: number;
    json?: boolean;
    es6?: boolean;
    escapeEverything?: boolean;
    wrap?: boolean;
    isScriptContext?: boolean;
    compact?: boolean;
    lowercaseHex?: boolean;
  };

  // ---- 特殊语法选项 ----

  // decorator 放在 export 前还是后(默认 false 即放在后面)
  decoratorsBeforeExport?: boolean;

  // Record/Tuple 的语法类型:#[...] 和 #{ } 或 |[ ]| 和 |{ }|(默认 "hash")
  recordAndTupleSyntaxType?: "hash" | "bar";

  // |> 管道运算符的 topic token(默认 "%")
  topicToken?: "%" | "#" | "@@" | "^^";

  // import attributes 使用 with 还是 assert 关键字
  importAttributesKeyword?: "with" | "assert" | "with-legacy";

  // ---- Source Map ----

  // 是否生成 source map(默认 false)
  sourceMaps?: boolean;

  // source map 的根路径
  sourceRoot?: string;

  // source map 中的文件名
  sourceFileName?: string;

  // 输入的 source map(用于 map 的 map)
  inputSourceMap?: string | object;

  // ---- 实验性 ----

  // 实验性:尽量保留原始代码格式(需要 @babel/parser 的 tokens 选项)
  experimental_preserveFormat?: boolean;
}

GeneratorResult 接口

interface GeneratorResult {
  // 生成的代码字符串
  code: string;

  // source map 对象(sourceMaps=false 时为 null)
  map: {
    version: number;
    sources: string[];
    names: string[];
    sourceRoot?: string;
    sourcesContent?: string[];
    mappings: string;   // VLQ 编码的位置映射
    file: string;
  } | null;

  // 解码后的 source map(内部使用,通常不需要)
  decodedMap?: DecodedSourceMap;

  // 原始映射数组(内部使用)
  rawMappings?: Mapping[];
}

@babel/core 类型详解

转换函数签名

import {
  transformSync,
  transformAsync,
  transform,
  transformFileSync,
  transformFileAsync,
  parseSync,
  parseAsync,
} from "@babel/core";

// 同步转换代码字符串
transformSync(
  code: string,
  options?: TransformOptions
): BabelFileResult | null;

// 异步转换代码字符串(支持异步插件)
transformAsync(
  code: string,
  options?: TransformOptions
): Promise<BabelFileResult | null>;

// 回调形式(较少使用)
transform(
  code: string,
  options: TransformOptions | undefined,
  callback: (err: Error | null, result: BabelFileResult | null) => void
): void;

// 同步转换文件(自动读取文件内容)
transformFileSync(
  filename: string,
  options?: TransformOptions
): BabelFileResult | null;

// 异步转换文件
transformFileAsync(
  filename: string,
  options?: TransformOptions
): Promise<BabelFileResult | null>;

// 只解析,不转换(同步)
parseSync(
  code: string,
  options?: TransformOptions
): t.File | null;

// 只解析,不转换(异步)
parseAsync(
  code: string,
  options?: TransformOptions
): Promise<t.File | null>;

BabelFileResult 接口

interface BabelFileResult {
  // 生成的代码(code: false 时为 null)
  code: string | null | undefined;

  // source map 对象(sourceMaps: false 时为 null)
  map: object | null | undefined;

  // AST(ast: true 时才有值)
  ast: t.File | null | undefined;

  // 外部依赖(被 ignore 匹配到的文件)
  ignored?: boolean;

  // 外部依赖文件路径
  externalDependencies?: Set<string>;
}

TransformOptions 接口(重要字段)

interface TransformOptions {
  // ---- 输入文件信息 ----

  // 关联的文件名(影响配置文件查找、source map、错误信息)
  filename?: string;

  // 相对文件名(用于 source map 的 sources 字段)
  filenameRelative?: string;

  // 工作目录(配置文件相对路径基准)
  cwd?: string;

  // ---- 输出控制 ----

  // 是否生成 code 字符串(默认 true)
  code?: boolean;

  // 是否在结果中包含 AST(默认 false,开启后 ast 字段有值)
  ast?: boolean;

  // 是否克隆输入 AST(默认 true,避免 traverse 修改原始 AST)
  cloneInputAst?: boolean;

  // ---- 插件与预设 ----

  // 插件列表
  // 可以是:字符串、[字符串, options]、插件函数、[插件函数, options]
  plugins?: PluginItem[];

  // 预设列表(与 plugins 格式相同)
  presets?: PluginItem[];

  // ---- 语法模式 ----

  // 模块类型(同 ParserOptions.sourceType)
  sourceType?: "script" | "module" | "commonjs" | "unambiguous";

  // ---- 配置文件 ----

  // 项目根配置文件路径(false 禁用)
  configFile?: string | false | boolean;

  // 是否搜索 .babelrc(默认 true)
  babelrc?: boolean;

  // 哪些包允许搜索 babelrc
  babelrcRoots?: boolean | MatchPattern | MatchPattern[];

  // 项目根目录
  root?: string;

  // 根目录查找模式
  rootMode?: "root" | "upward" | "upward-optional";

  // 当前环境(读取 env[envName] 的配置,默认读 NODE_ENV 或 "development")
  envName?: string;

  // ---- Source Map ----

  // 是否生成 source map
  // true: 独立 map 对象;"inline": 追加到代码末尾;"both": 两者都要
  sourceMaps?: boolean | "inline" | "both";

  // source map 中的文件名
  sourceFileName?: string;

  // source map 根路径
  sourceRoot?: string;

  // ---- 代码生成 ----

  // 保留原始行号(默认 false)
  retainLines?: boolean;

  // 紧凑输出(默认 "auto")
  compact?: boolean | "auto";

  // 压缩输出(默认 false)
  minified?: boolean;

  // 是否保留注释(默认 true)
  comments?: boolean;

  // 自定义注释过滤
  shouldPrintComment?: (comment: string) => boolean;

  // 传给 parser 的额外选项
  parserOpts?: ParserOptions;

  // 传给 generator 的额外选项
  generatorOpts?: GeneratorOptions;

  // ---- 条件配置 ----

  // 环境特定配置
  env?: { [envKey: string]: TransformOptions };

  // 条件覆盖配置
  overrides?: TransformOptions[];

  // 包含匹配的文件(与 test 同义)
  test?: MatchPattern | MatchPattern[];
  include?: MatchPattern | MatchPattern[];

  // 排除匹配的文件
  exclude?: MatchPattern | MatchPattern[];
  ignore?: MatchPattern | MatchPattern[];
  only?: MatchPattern | MatchPattern[];

  // ---- 优化 ----

  // Babel 可以对代码做的假设(用于优化输出体积)
  assumptions?: { [assumption: string]: boolean };

  // 目标环境(支持 browserslist 格式)
  targets?: string | string[] | { [key: string]: string };
}

PluginObj 接口(插件格式)

编写 Babel 插件时,插件函数返回一个 PluginObj

import { PluginObj, PluginPass } from "@babel/core";
import traverse, { NodePath } from "@babel/traverse";
import * as t from "@babel/types";

// S 是 state 的类型,默认是 PluginPass
// PluginPass 是 Babel 传给插件的内置 state 对象
type PluginObj<S extends PluginPass = PluginPass> = {
  // 插件名称(可选,用于错误信息)
  name?: string;

  // 在所有转换开始前调用(this 是 state 实例)
  pre?: (this: S, file: BabelFile) => void | Promise<void>;

  // AST 访问者(核心)
  visitor?: Visitor<S>;

  // 在所有转换完成后调用
  post?: (this: S, file: BabelFile) => void | Promise<void>;

  // 修改 parser/generator 选项
  manipulateOptions?: (
    options: TransformOptions,
    parserOpts: ParserOptions
  ) => void;

  // 继承另一个插件
  inherits?: PluginAPI;
};

// PluginPass 是 state 的内置类型(插件 visitor 里的 this 和 state 参数)
class PluginPass {
  file: BabelFile;
  key: string | undefined | null;
  opts: object;                  // 插件的配置选项
  cwd: string;                   // 工作目录
  filename: string | undefined;  // 当前文件路径

  // 存/取任意数据(跨 visitor 共享状态)
  set(key: unknown, val: unknown): void;
  get(key: unknown): any;

  // 判断是否可以使用某个 helper
  availableHelper(name: string, versionRange?: string): boolean;

  // 添加 helper import(插件注入 helper 函数时使用)
  addHelper(name: string): t.Expression;

  // 生成带代码位置的错误信息
  buildCodeFrameError(node: t.Node, msg: string, Error?: typeof Error): Error;
}

TypeScript 使用模式

1. 正确为 NodePath 加泛型

import traverse, { NodePath } from "@babel/traverse";
import * as t from "@babel/types";

const ast = parse(`foo(1, 2)`);

traverse(ast, {
  // visitor 键名决定了 path 的泛型类型
  // 这里 path 自动被推断为 NodePath<t.CallExpression>
  CallExpression(path) {
    // path.node 类型是 t.CallExpression,有完整类型提示
    const callee = path.node.callee;       // t.Expression | t.Super | t.V8IntrinsicIdentifier
    const args = path.node.arguments;      // (t.Expression | t.SpreadElement | ...)[]
  },

  // 也可以显式标注(当 TypeScript 推断失败时)
  "StringLiteral|NumericLiteral"(path: NodePath<t.StringLiteral | t.NumericLiteral>) {
    console.log(path.node.value);
  },
});

2. 用 isXxx() 做类型收窄

traverse(ast, {
  CallExpression(path) {
    const callee = path.node.callee;
    // callee 类型是 t.Expression | t.Super | t.V8IntrinsicIdentifier
    // 直接访问 .name 会报错

    // 用 isXxx 收窄
    if (t.isIdentifier(callee)) {
      // 这里 callee 类型收窄为 t.Identifier
      console.log(callee.name); // 类型安全
    }

    if (t.isMemberExpression(callee)) {
      // 这里 callee 类型收窄为 t.MemberExpression
      // 继续收窄 property
      if (!callee.computed && t.isIdentifier(callee.property)) {
        console.log(callee.property.name);
      }
    }

    // 带 opts 的收窄(同时检查属性值)
    if (t.isIdentifier(callee, { name: "console" })) {
      // callee 是名为 "console" 的 Identifier
    }
  },
});

3. state 对象的类型标注

import { NodePath, Visitor } from "@babel/traverse";
import * as t from "@babel/types";

// 定义 state 类型
interface MyState {
  functionCount: number;
  stringLiterals: string[];
  filename: string;
}

const initialState: MyState = {
  functionCount: 0,
  stringLiterals: [],
  filename: "",
};

// 方式一:traverse 的泛型形式(state 完全类型安全)
traverse<MyState>(
  ast,
  {
    FunctionDeclaration(path, state) {
      // state 类型是 MyState,有类型提示
      state.functionCount++;
    },
    StringLiteral(path, state) {
      state.stringLiterals.push(path.node.value);
    },
  },
  undefined,
  initialState
);

console.log(initialState.functionCount); // 访问结果

// 方式二:定义 Visitor 变量(复用 visitor)
const myVisitor: Visitor<MyState> = {
  FunctionDeclaration(path, state) {
    state.functionCount++;
  },
  StringLiteral(path, state) {
    state.stringLiterals.push(path.node.value);
  },
};

traverse<MyState>(ast, myVisitor, undefined, initialState);

4. 编写类型安全的 Babel 插件

import { PluginObj, PluginPass } from "@babel/core";
import * as t from "@babel/types";

// 定义插件选项类型
interface MyPluginOptions {
  stripConsole?: boolean;
  targetVar?: string;
}

// 扩展 PluginPass 以添加自定义字段
interface MyPluginState extends PluginPass {
  opts: MyPluginOptions; // 覆盖 opts 的类型
  removedCount: number;
}

// 导出插件函数
export default function myPlugin(): PluginObj<MyPluginState> {
  return {
    name: "my-plugin",

    pre(this: MyPluginState) {
      this.removedCount = 0;
    },

    visitor: {
      ExpressionStatement(path, state) {
        if (!state.opts.stripConsole) return;

        const expr = path.node.expression;
        if (
          t.isCallExpression(expr) &&
          t.isMemberExpression(expr.callee) &&
          t.isIdentifier(expr.callee.object, { name: "console" })
        ) {
          path.remove();
          state.removedCount++;
        }
      },

      Identifier(path, state) {
        const targetVar = state.opts.targetVar;
        if (!targetVar) return;

        if (
          path.node.name === targetVar &&
          path.isReferenced()
        ) {
          path.replaceWith(t.identifier("__renamed__" + targetVar));
        }
      },
    },

    post(this: MyPluginState) {
      if (this.opts.stripConsole) {
        console.info(`Removed ${this.removedCount} console calls`);
      }
    },
  };
}

5. 遍历时避免 any 的最佳实践

import traverse, { NodePath } from "@babel/traverse";
import * as t from "@babel/types";

// 不好的写法:丢失类型信息
traverse(ast, {
  CallExpression(path: any) { // any 丢失所有类型检查
    path.node.callee.name; // 不安全,callee 不一定有 name
  },
});

// 好的写法一:利用 visitor 键名自动推断
traverse(ast, {
  CallExpression(path) { // path 自动推断为 NodePath<t.CallExpression>
    const { callee } = path.node;
    if (t.isIdentifier(callee)) { // 用 isXxx 收窄
      callee.name; // 类型安全
    }
  },
});

// 好的写法二:提取为具名函数,显式标注类型
function visitCallExpression(path: NodePath<t.CallExpression>): void {
  const { callee, arguments: args } = path.node;

  if (t.isIdentifier(callee)) {
    console.log(`调用函数: ${callee.name}`);
  } else if (t.isMemberExpression(callee) && !callee.computed) {
    t.assertIdentifier(callee.object);
    t.assertIdentifier(callee.property);
    console.log(`调用方法: ${callee.object.name}.${callee.property.name}`);
  }
}

traverse(ast, { CallExpression: visitCallExpression });

// 好的写法三:处理 NodePath 数组(path.get 返回联合类型)
traverse(ast, {
  ArrayExpression(path) {
    const elements = path.get("elements"); // NodePath<...>[]
    if (!Array.isArray(elements)) return;

    for (const element of elements) {
      if (element.isStringLiteral()) {
        // element 收窄为 NodePath<t.StringLiteral>
        console.log(element.node.value);
      }
    }
  },
});

6. 处理 MemberExpression 的计算属性问题

由于 MemberExpression 是联合类型,property 的类型取决于 computed 字段:

traverse(ast, {
  MemberExpression(path) {
    const { node } = path;

    if (node.computed) {
      // node.property 类型是 t.Expression
      // node 类型收窄为 MemberExpressionComputed
      console.log("计算属性:", node.property.type);
    } else {
      // node.property 类型是 t.Identifier | t.PrivateName
      if (t.isIdentifier(node.property)) {
        console.log("属性名:", node.property.name);
      }
    }
  },
});

7. 使用 path.scope 做安全重命名

import traverse from "@babel/traverse";

traverse(ast, {
  Identifier(path) {
    const { name } = path.node;
    if (!/^_0x[0-9a-f]+$/i.test(name)) return;

    const binding = path.scope.getBinding(name);
    if (!binding) return;

    // 确认是声明处(避免重复重命名)
    if (binding.path.node !== path.node) return;

    // generateUid 保证新名称在当前作用域不冲突
    const newName = path.scope.generateUid("var");
    // rename 自动更新所有引用(binding.referencePaths)
    path.scope.rename(name, newName);
  },
});

8. 完整的 TypeScript 工作流示例

import { parse } from "@babel/parser";
import traverse, { NodePath } from "@babel/traverse";
import generate from "@babel/generator";
import * as t from "@babel/types";

const sourceCode = `
import { foo } from "bar";
const result = foo(1, "hello", true);
`;

// 1. 解析(返回类型明确为 t.File)
const ast: t.File = parse(sourceCode, {
  sourceType: "module",
  plugins: ["typescript"],
});

// 2. 遍历并修改
traverse(ast, {
  // ImportDeclaration 的 path 类型为 NodePath<t.ImportDeclaration>
  ImportDeclaration(path) {
    // source.value 是字符串,类型安全
    if (path.node.source.value === "bar") {
      path.node.source = t.stringLiteral("baz");
    }
  },

  // CallExpression 的 path 类型为 NodePath<t.CallExpression>
  CallExpression(path) {
    const { callee, arguments: args } = path.node;

    if (!t.isIdentifier(callee, { name: "foo" })) return;

    // 将所有参数中的字符串字面量转为大写
    const newArgs = args.map((arg) => {
      if (t.isStringLiteral(arg)) {
        return t.stringLiteral(arg.value.toUpperCase());
      }
      return arg;
    });

    path.replaceWith(
      t.callExpression(callee, newArgs)
    );
    path.skip(); // 防止递归处理新节点
  },
});

// 3. 生成代码
const { code, map } = generate(ast, {
  comments: true,
  jsescOption: { minimal: true },
});

console.log(code);
// import { foo } from "baz";
// const result = foo(1, "HELLO", true);

注意事项与踩坑

@babel/traverse 的默认导出问题

// 编译到 CJS 时,traverse 是 module.exports.default
// 需要这样导入(配合 esModuleInterop: true):
import traverse from "@babel/traverse";

// 如果不用 esModuleInterop,需要这样:
import _traverse from "@babel/traverse";
const traverse = (_traverse as any).default ?? _traverse;

// @babel/generator 同理
import _generate from "@babel/generator";
const generate = (_generate as any).default ?? _generate;

NodePath.get() 的返回类型

// path.get() 返回 NodePath | NodePath[]
// 当字段是数组时返回数组,需要用 Array.isArray 判断
const bodyPath = path.get("body");
if (Array.isArray(bodyPath)) {
  // bodyPath 是 NodePath[]
  bodyPath.forEach((p) => { /* ... */ });
} else {
  // bodyPath 是 NodePath
}

cloneNode 用于避免节点共享问题

// 同一个节点对象不能挂载在树的两处
// 错误写法:
const id = t.identifier("foo");
const decl = t.variableDeclaration("const", [
  t.variableDeclarator(id, null),
  t.variableDeclarator(id, null), // 共享 id,会报错
]);

// 正确写法:
const decl2 = t.variableDeclaration("const", [
  t.variableDeclarator(t.identifier("foo"), null),
  t.variableDeclarator(t.cloneNode(t.identifier("foo")), null),
]);

replaceWith 后立即 skip()

traverse(ast, {
  StringLiteral(path) {
    // 替换为新的 StringLiteral 会再次触发本 visitor,造成无限循环
    path.replaceWith(t.stringLiteral(path.node.value.trim()));
    path.skip(); // 跳过新节点的遍历,打破循环
  },
});


最佳实践

使用 TypeScript 类型缩小节点类型:在 @babel/traverse 的 Visitor 函数中,收到的 path 是联合类型;用类型守卫(if (t.isIdentifier(path.node)))缩小后,IDE 会自动补全节点的具体属性,避免手写字符串访问。

t.is* 系列函数做运行时类型检查t.isBinaryExpression(node) 等函数比手动 node.type === 'BinaryExpression' 更安全——@babel/types 会处理别名(如 t.isExpression 匹配所有表达式类型),减少遗漏情况。

构建节点时用 Builder 函数:不要手写 { type: 'Identifier', name: 'x' },用 t.identifier('x') 让 Babel 自动填充所有必须字段(extra、位置信息等),避免缺少必须字段导致代码生成失败。

TypeScript 项目中导入 @babel/typesNode 联合类型import type { Node, Statement, Expression } from '@babel/types' 为所有节点的联合类型,可以在自定义函数参数类型中使用,得到完整的类型推断。

利用 assertXxx 系列做防御式编程t.assertIdentifier(node) 在节点类型不匹配时抛 TypeError,在调试阶段替代手动 if (!t.isIdentifier(node)) throw new Error(...) 更简洁;生产代码改用 t.isIdentifier 做条件分支。


常见陷阱

陷阱:path.node 类型太宽导致属性访问报 TypeScript 错误

现象: path.node.nameProperty 'name' does not exist on type 'Node'
原因: path.nodeNode 联合类型,只有 Identifiername 属性;TypeScript 不知道当前是哪个具体类型。
解决: 在 Visitor 中使用对应的 key(如 Identifier(path) { ... }),TypeScript 会自动推断 path.nodeIdentifier 类型;或用 if (t.isIdentifier(path.node)) 类型守卫。

陷阱:NodePathNode 混用导致错误

现象:path 传入期望 Node 的函数,或将 path.node 传入期望 NodePath 的方法。
原因: NodePath 包含 node(AST 节点)+ 作用域信息 + 父级引用等;它们是不同的对象,不可互换。
解决: 规范命名:pathNodePathnodeNode;需要节点时用 path.node,需要路径操作(replaceskip)时用 path

陷阱:t.cloneNode 浅拷贝共享子节点引用

现象: 修改克隆节点的子节点,原节点也被修改。
原因: t.cloneNode(node) 默认浅拷贝,子节点还是同一引用;t.cloneNode(node, true) 才是深拷贝。
解决: 需要独立副本时用 t.cloneDeepWithoutLoc(node)t.cloneNode(node, true)(第二参数为 true 深拷贝)。


参见

Babel AST入门
js-ast-notes
混淆还原

阅读更多

Web 安全基础

1. HTML 转义(服务端渲染必须): 2. CSP(Content Security Policy): 3. HttpOnly Cookie:防止 JS 读取会话 Cookie: 4. 前端框架防护: 攻击者在第三方网站构造一个表单,诱导已登录用户提交,浏览器会自动携带目标站的 Cookie。 触发条件: 1. 用户已登录目标网站(Cookie 有效) 2. 目标 API 仅凭 Cookie 识别用户身份 3. 请求来源未验证 1. CSRF Token(推荐): 2. SameSite Cookie: 3. 验证 Origin/Referer 头:

By yellowdog

HTTP 协议深度指南

HTTP(HyperText Transfer Protocol)是 Web 的基础传输协议,基于 TCP/IP,采用请求/响应模型。 相关文档:Web安全基础(/web-an-quan-ji-chu/) FastAPI完全指南(/fastapi-wan-quan-zhi-nan/) Nginx完全指南(/nginx-wan-quan-zhi-nan/) 幂等性:多次执行相同请求,服务器状态结果相同。PUT /users/1 多次执行结果一致;POST /users 每次创建新资源,非幂等。 浏览器直接从本地缓存读取,不向服务器发送请求。 缓存命中时,状

By yellowdog

系统设计基础

SLA 对照表: 选择建议:无状态服务(Web 层、API 层)优先水平扩展;数据库初期垂直扩展,达到瓶颈后考虑分库分表或读写分离。 缓存穿透(查询不存在的 key,每次都打到 DB): 缓存击穿(热点 key 过期,瞬间大量请求打到 DB): 缓存雪崩(大量 key 同时过期,或缓存服务宕机): 令牌桶 Python 实现: Redis 实现分布式限流(滑动窗口): URL 命名规则: Cursor 分页响应格式: 雪花算法结构(64 bit): 定义:分布式系统不能同时满足以下三个特性: 在分布式环境中 P 是必须保证的,所以实际是 CP vs AP

By yellowdog

算法思路与模板

二分查找要求序列有序,每次将搜索范围缩减一半,时间复杂度 O(log n)。 两个指针从两端向中间收缩,常用于有序数组。 滑动窗口维护一个满足条件的区间 left, right,right 不断向右扩张,条件不满足时收缩 left。 滑动窗口通用框架: 1. 确定"子问题":原问题可以分解为哪些规模更小的同类问题 2. 定义 dpi 或 dpij 的含义,要足够清晰 3. 推导状态转移方程 4. 确定初始状态(边界条件) 5. 确定计算顺序(确保依赖的子问题先计算) 每件物品最多选一次。dpj = 容量为 j 时的最大价值,逆序遍历容量防止重复选取。 每

By yellowdog