Token导航 LogoToken导航TokenDH.com

TS 7:AI 生成式代码的拐点

更新时间 2026-07-09来源 浮之静正文 2.2万字阅读约 70分钟8 张图片

决定代码生成速度的不只是模型,还应包括各种开发基建!

TypeScript 7 已经可以正式安装和使用。对只跑 tsc 的项目,它接近一次直接版本升级;对真实工程,它更像一次工具链边界重排。

我的体感很直接:把本地项目从 TS6 切到 TS7 后,再跑全量类型检查,机器没有再进入风扇明显起转的高压状态(完全静音了)。这个感受和后面的测评数据一致:纯 tsc 从 4.38s 降到 0.60s,完整本地 gate 从 54.92s 降到 27.23s。对配置更低、散热更保守的机器来说,这类升级带来的收益不只是少等几秒,也可能是更低的发热、噪声和电量压力。

Native 大趋势
图片

TypeScript 7 不是孤立事件。过去几年,JavaScript / TypeScript 乃至 Python 这类动态语言生态里的大量热路径,都在从脚本层实现迁到 Go、Rust 或其他 compile-to-native 语言。补充阅读:Rust 在前端、ViteConf 2023:Vite 即将 Rust 化、AI 编程生态:Anthropic 收购 Bun 意味着什么?、下一代 Web 开发生态、浅谈 AI 编程、第一个 Agent 从 Pi 开始、关于 AI 编程的一些浅思、RL 局限与反思 & 细菌编程、Agent 趋势浅思:原生化 & CLI 化、AI 浪潮下的开发者,又该何去何从?

这不是语言崇拜,而是架构分层:

  • 语言 / 生态层: API、配置、插件、生态兼容、开发者体验
  • native core: parser、resolver、transform、bundle、lint、cache、调度

几个典型项目已经把这条路走得很清楚:

  • esbuild:esbuild[1] 是 Go native binary,核心卖点包括原生代码、并行和更少数据转换。它证明了 JS bundler / transformer 的热路径可以被数量级压缩,也长期被 Vite 等工具复用。
  • Vite / VoidZero:VoidZero[2] 的方向是 Rolldown + Oxc:统一 AST、resolver、module interop,并逐步让 Vite 生态由 Rolldown / Oxc 驱动。它不是只做一个更快的 dev server,而是继续下探到 bundler、parser、resolver、linter、transformer 的统一底座。
  • Bun:Bun[3] 以 Rust + JavaScriptCore 为核心,把 runtime、package manager、test runner、bundler 压进单一 bun 可执行文件。它代表的是 Node 生态里分散执行路径的 native 化整合。
  • Turborepo:Turborepo[4] 是面向 JS/TS codebase 的 Rust build system。monorepo 调度、缓存、任务图这类 CI / 本地开发热路径,也在向 native core 迁移。
  • Python / Astral:uv[5] 是 Rust 写的 Python package / project manager,把 pippip-toolspipxpoetrypyenvvirtualenv 等路径收敛到一个工具;Ruff[6] 是 Rust 写的 linter / formatter,把 lint、format 这类编辑热路径 native 化。Python 生态也在把包管理、解析、格式化、检查这类低层高频路径下沉。

此趋势背后的判断:现代代码库的瓶颈已经不是“能不能表达构建逻辑”,而是“能不能在大规模代码和高频变更下保持低延迟反馈”。

AI 生成式代码会进一步放大这个压力。过去人类写代码,工具链慢一点只是体感差;现在 agent 可以连续生成、修改、回滚、再生成,慢工具链会直接限制 agent 的搜索空间和修复频率。

所以未来的关键基础设施会越来越像这样:

native verifier / transformer / scheduler
  + JS/TS plugin and configuration surface
  + local-first cache and sandbox
  + machine-readable diagnostics
  + agent-friendly repair loop

TypeScript 7 的 native CLI 正好落在这个趋势上。它保留 TypeScript 作为类型系统和工程契约的地位,同时把高频验证路径向 native core 推进。对 AI coding 来说,这比单纯“编译快了”更重要:它让类型系统更适合进入生成系统的内循环。

除了开发基建分层,产品技术分层也会越来越多:比如 Codex 桌面应用上层使用 Electron 套壳 UI,底层使用 Rust 作为核心。

TS 7 迁移

是否值得迁?

我的结论:值得迁,但真实工程不要直接把 typescript 这个包名指向 TS7。先看这次 30 万行级(项目 Noi,前几天刚写过Noi 编程实战:Fable 没那么强,GPT 也没那么弱)。TS/TSX 仓库的实测结果(在 AI 浪潮下的开发者,又该何去何从?文章后半部分已经介绍过 TS 7 技术背景,这里不再赘述):

图片

从表可以看到:裸 tsc 从 4.38s 到 0.60s,完整本地 gate 从 54.92s 到 27.23s。前者证明 TS7 native CLI 的 compiler 收益,后者证明真实开发等待也能明显缩短。至于为什么不能直接替换 typescript 包名,下一节展开。

安装路径

微软 TypeScript 团队在 2026-07-08 发布 Announcing TypeScript 7.0[7]。官方给出的性能对比图也很直接:

图片

这次迁移的关键不是“把 typescript 升到 7”,而是把 TS7 native CLI 和 TS6 compiler API 分开。官方建议的直观形态是 side-by-side:

{
  "devDependencies": {
    "@typescript/native": "npm:typescript@^7.0.2",
    "typescript": "npm:@typescript/typescript6@^6.0.2"
  }
}

也就是:

@typescript/native -> TS7 CLI / native tsc
typescript         -> TS6 compiler API

本仓库最终采用同一条主线,只是在本地工具链上继续补齐执行路径:

{
  "@typescript/native":"npm:typescript@7.0.2",
  "typescript":"npm:@typescript/typescript6@6.0.2",
  "tsx":"4.23.0",
  "ts-node":"^10.9.2",
  "typescript-eslint":"^8.63.0"
}

这里 ts-node 只是暂留依赖,不再作为主执行路径(后续被 tsx 所替代)。真实运行边界如下:

pnpm exec tsc         -> TS7 native CLI
pnpm exec tsc6        -> TS6 alias CLI
require("typescript") -> TS6 compiler API
node --import tsx     -> TypeScript 脚本执行
轻量转译 / 结构扫描     -> 不走完整 compiler API

需要修的是工具链入口:

  • 依赖 createProgramtranspileModule 或 AST 类型信息的路径,继续走 TS6 alias。
  • TypeScript 脚本执行从 ts-node/register/transpile-only 迁到 tsx
  • 只做片段转译或语法结构判断的脚本,改成更轻路径,不再默认加载完整 typescript
  • tsconfig 清理 TS7 已推到硬错误边界的旧配置,例如旧的 moduleResolutionmodulebaseUrlignoreDeprecations

这样拆完以后,tsc 的性能收益可以立即进入主检查链路;旧 API 兼容风险被压在 TS6 alias;后续发现的架构边界、文档预算、打包泄漏、测试布局问题,也不会和 TS7 安装问题混在一起判断。

性能测评

这一节只看两件事:compiler 本体快了多少,以及完整本地 gate 少等多久。

图片

real 是开发者等待时间;CPU sec = user + sys,代表机器实际计算消耗;CPU% 代表并行利用程度。C2 不是纯 compiler benchmark,它衡量的是本仓库一次完整本地质量门的成本。

基准条件

图片

TS6 和 TS7 在同一台机器、同一仓库、同一脚本、同一采样规则下对比。完整脚本放在附录 A,.txt 输出节选放在附录 B。

代码规模

图片

C2 每轮都是 2241 tests / 2241 pass / 0 fail

TS6 基线

TS6 跑了三批。C1 基本稳定,使用全部 15 个 counted samples;C2 对系统波动更敏感,第一批在负载影响下放大到 78.30s,明显高于后两批。因此主比较使用后两批 6 个 counted samples,全样本 C2 median 61.50s 只作为系统波动参考。

图片

TS7 结果

图片

怎么读

纯 tsc 的结论最硬:4.38s -> 0.60s,约 7.30x;CPU sec 也从 7.67s 降到 2.60s。这不是单纯“更烧 CPU 换时间”,而是更高并行度、更短等待、更低总计算消耗同时出现。

C2 的 54.92s -> 27.23s 是完整本地 gate 的收益,约 2.02x。它包含测试、package typecheck、runner 启动和执行路径变化,所以不能把 C2 的 CPU sec 降幅直接解释成 TypeScript compiler 单独变快。正确读法是:compiler 本体提升非常明确,完整开发链路也获得了稳定的一半耗时下降。

AI 代码基建

TypeScript 7 对 AI 代码生成的价值,不只是“开发者少等几秒”。它让类型验证更适合进入生成式开发的内循环。

AI 代码的瓶颈正在从“能不能生成”转向“能不能快速验证”。模型可以很快产出一个 patch,但工程系统必须快速回答:

  • 类型是否成立?
  • 接口是否匹配?
  • 重构是否破坏调用点?
  • 生成代码是否误跨运行时边界?
  • 修复一次之后,下一轮反馈多久回来?

TypeScript 在这里更像确定性验证器。它把模型输出从“看起来合理的文本”压到可执行的工程约束里:

AI 生成候选代码
  -> tsc / lint / tests
  -> 结构化错误
  -> agent 修复
  -> 再验证

这个循环的成本决定了 AI 编程系统能不能规模化。一次 tsc --noEmit 如果要等 4-5 秒,agent 会倾向于少跑检查、批量猜测、延迟发现错误;如果同一轮检查降到 0.60 秒,它就可以更频繁地把类型系统放进内循环。

这会直接改变几类工作流:

  • 多文件重构:更快发现调用点、泛型、导入和声明漂移。
  • 生成新模块:可以把 tsc --noEmit 放进每轮候选验证,而不是最后兜底。
  • 自动修复类型错误:错误、修复、复查循环更短,减少无效修复轮次。
  • 大批量机械迁移:类型系统成为高频过滤器,先筛掉不成立的候选 patch。
  • 本地-first agent:不依赖远端 CI 才知道类型是否破坏,反馈留在本机。

这也是为什么 full gate 的 2.02x 同样重要。AI 生成代码不会只触发 tsc,它还会触发测试、lint、边界检查、打包检查。真正能支撑 agent 的不是单点 benchmark,而是一条低延迟、可重复、可定位的本地验证链。

从这个角度看,TypeScript 7 的 native CLI 已经不是普通性能优化,而是 AI 生成式代码的重要基础设施。在 AI 应用、agent 工具和前端工作台里,TypeScript 仍是最常用的工程语言之一。它的验证链路越快,生成式开发的有效迭代上限就越高:

更快的 tsc
  -> 更短的验证回路
  -> 更高频的自动修复
  -> 更少把错误推迟到 CI
  -> 更适合 agent 在本地连续工作

这也回到安装策略:不要把 typescript 这个包名直接切到 TS7。AI 工具链调用的不只是 tsc,还有 lint parser、AST 工具、测试注册器、代码索引器、编辑器集成、codemod、脚本执行器。很多工具仍通过 require("typescript") 使用旧 compiler API。让 TS7 native CLI 负责高频验证,让 TS6 alias 承接这些旧 API,agent 才能稳定收到类型错误和测试失败,而不是先撞上工具兼容问题。

所以这次升级的重要性不只是性能数字,而是它让 TypeScript 更接近生成式代码系统需要的形态:

CLI 验证路径足够快;
旧 compiler API 有明确承接;
本地 gate 可以高频运行;
错误反馈足够确定;
agent 可以围绕验证器闭环修复。

AI 生成代码越多,类型检查就越不应该停留在低频 CI 事件里。它应该成为本地生成循环里的热路径。

结语

TypeScript 7 值得迁,但它不是“把 typescript 这个包名直接升到 7”。真实工程更稳的路径是:TS7 native CLI 负责高频 tsc 验证;TS6 alias 承接仍依赖旧 compiler API 的工具;TS 脚本执行迁到 tsx(放弃 ts-node);自有转译和结构扫描尽量减少对完整 TS API 的依赖。

这次在 30 万行级 TS/TSX 仓库上的结果很直接:裸 tsc 约 7.30x,完整 typecheck --full 约 2.02x。前者说明 compiler 路径已经进入 native 化收益区,后者说明真实本地质量门也能明显缩短。

对 AI 生成式代码来说,这个升级的价值不止是少等几秒。类型检查越快,agent 越能把“生成 → 验证 → 修复 → 再验证”放进本地热路径。TS7 的关键意义,是把 TypeScript 从低频 CI 校验推进到高频、本地、确定性的生成式开发基础设施。

迁移时最需要避免的误判是:把 ESLint、test runner、webpack、架构边界债务都归因到 TS7。先把 CLI 验证、旧 compiler API、脚本执行和轻量转译的职责分清,TS7 的收益会非常直接;分不清,升级就会变成工具链噪音。

附录

附录 A:通用测评脚本

脚本只约定两类测评:C1 是纯 tsc 检查,C2 是项目自己的完整本地质量门。具体命令都通过参数传入:

node measure-typescript-check.mjs \
  --profile baseline \
  --date 2026-07-09 \
  --tsc-cmd "pnpm exec tsc6 --noEmit --pretty false" \
  --full-check-cmd "pnpm typecheck --full" \
  --tsc-warmup 1 \
  --tsc-runs 5 \
  --full-warmup 1 \
  --full-runs 3

不传 --out 时,脚本会按 typescript-check-${profile}-${date}.txt 自动命名。输出内容包含命令映射、Batch Summary、C1/C2 样本、环境快照、Top CPU 进程和说明,方便后续回看采样条件,而不是只保留结论数字。

脚本模板(仅供参考,具体实现可让 AI 辅助生成):

#!/usr/bin/env node
import { spawn } from "node:child_process";
import { writeFileSync } from "node:fs";
import os from "node:os";
import process from "node:process";

const profile = readOption("--profile", "ts");
const runDate = readOption("--date", new Date().toISOString().slice(0, 10));
const startedAt = new Date().toISOString();
const outFile = readOption("--out", `typescript-check-${profile}-${runDate}.txt`);
const shellBin = readOption("--shell-bin", "sh");
const timeBin = readOption("--time-bin", "/usr/bin/time");
const title = readOption(
  "--title",
  profile === "baseline"
    ? "TypeScript Compile / Check Speed Baseline"
    : `TypeScript Compile / Check Speed ${profile.toUpperCase()}`,
);

// C1 keeps the compiler-only path isolated.
// C2 measures the local full gate that developers actually wait for.
const cases = [
  {
    id: "C1",
    label: "tsc",
    command: readOption("--tsc-cmd", "pnpm exec tsc --noEmit --pretty false"),
    warmup: numberOption("--tsc-warmup", 1),
    runs: numberOption("--tsc-runs", 5),
  },
  {
    id: "C2",
    label: "full gate",
    command: readOption("--full-check-cmd", "pnpm typecheck"),
    warmup: numberOption("--full-warmup", 1),
    runs: numberOption("--full-runs", 3),
  },
];

const records = [];
const environmentRows = await collectEnvironmentSnapshot();
const topCpu = await captureCommand(
  readOption("--top-cpu-cmd", "ps -axo pid,pcpu,pmem,comm | sort -nrk 2 | head -n 12"),
);
let failed = false;

for (const item of cases) {
  const totalRuns = item.warmup + item.runs;

  for (let index = 1; index <= totalRuns; index += 1) {
    const phase = index <= item.warmup ? "warmup" : "counted";
    const run = index <= item.warmup ? index : index - item.warmup;
    const result = await runMeasured(item.command);
    const tests = extractTestStats(`${result.stdout}\n${result.stderr}`);

    const record = {
      caseId: item.id,
      label: item.label,
      command: item.command,
      phase,
      run,
      status: result.status,
      real: result.real,
      user: result.user,
      sys: result.sys,
      cpuSec: result.user + result.sys,
      cpuPct: result.real > 0 ? ((result.user + result.sys) / result.real) * 100 : 0,
      tests: tests.tests ?? "n/a",
      fail: tests.fail ?? "n/a",
    };

    records.push(record);

    // Stop on failure. Failed checks should not be mixed into performance data.
    if (result.status !== "pass") {
      failed = true;
      break;
    }
  }

  if (failed) {
    break;
  }
}

const report = renderReport();
writeFileSync(outFile, `${report}\n`);
process.stdout.write(`${report}\n`);

if (failed) {
  process.exit(1);
}

async function runMeasured(command) {
  return new Promise((resolve) => {
    const child = spawn(timeBin, ["-p", shellBin, "-c", command], {
      stdio: ["ignore", "pipe", "pipe"],
    });

    let stdout = "";
    let stderr = "";

    child.stdout.on("data", (chunk) => {
      stdout += chunk;
    });

    child.stderr.on("data", (chunk) => {
      stderr += chunk;
    });

    child.on("close", (exitCode) => {
      try {
        resolve({
          exitCode,
          status: exitCode === 0 ? "pass" : `fail:${exitCode}`,
          stdout,
          stderr,
          real: readTimeMetric(stderr, "real"),
          user: readTimeMetric(stderr, "user"),
          sys: readTimeMetric(stderr, "sys"),
        });
      } catch (error) {
        resolve({
          exitCode: exitCode ?? 1,
          status: "fail:time-parse",
          stdout,
          stderr: `${stderr}\n${error.message}`,
          real: 0,
          user: 0,
          sys: 0,
        });
      }
    });
  });
}

function readTimeMetric(text, key) {
  const matches = [...text.matchAll(new RegExp(`^${key}\\s+([0-9.]+)$`, "gm"))];
  const value = matches.at(-1)?.[1];

  if (value === undefined) {
    throw new Error(`Missing /usr/bin/time metric: ${key}`);
  }

  return Number(value);
}

function renderReport() {
  const lines = [];

  lines.push(title);
  lines.push("=".repeat(title.length));
  lines.push("");
  lines.push(`Recorded at : ${runDate}`);
  lines.push(`Timestamp   : ${startedAt}`);
  lines.push(`Profile     : ${profile}`);
  lines.push(`Output      : ${outFile}`);
  lines.push(`Host        : ${os.hostname()}`);
  lines.push(`Platform    : ${process.platform} ${process.arch}`);
  lines.push(`Node        : ${process.version}`);
  lines.push("");
  lines.push("CPU formula : cpu_seconds = user + sys");
  lines.push("              cpu_percent ~= (user + sys) / real * 100");
  lines.push("              Values over 100% mean multiple CPU cores were used.");
  lines.push("");
  lines.push(heading("Command Keys"));
  lines.push("");
  lines.push(renderBoxTable(
    ["Key", "Command"],
    cases.map((item) => [item.id, item.command]),
  ));
  lines.push("");
  lines.push(heading("Batch Summary"));
  lines.push("");
  lines.push(renderSummary(records));
  lines.push("");

  for (const item of cases) {
    lines.push(heading(`${item.id} Samples`));
    lines.push("");
    lines.push(renderSamples(records.filter((record) => record.caseId === item.id)));
    lines.push("");
  }

  lines.push(heading("Environment Snapshot"));
  lines.push("");
  lines.push(renderBoxTable(["Key", "Status", "Value"], environmentRows));
  lines.push("");
  lines.push(heading("Top CPU Processes At Batch Start"));
  lines.push("");
  lines.push(topCpu.value || "n/a");
  lines.push("");
  lines.push(heading("Notes"));
  lines.push("");
  lines.push(renderBoxTable(
    ["#", "Note"],
    [
      ["1", "Warm-up runs are recorded but excluded from medians."],
      ["2", "C1 measures the compiler-only check path."],
      ["3", "C2 measures the local full gate developers actually wait for."],
      ["4", "CPU% is approximate and machine-load-sensitive; compare repeated runs."],
      ["5", "Failed checks stop the batch so failed output is not mixed into performance medians."],
    ],
  ));

  return lines.join("\n");
}

function renderSummary(allRecords) {
  const counted = allRecords.filter((record) => record.phase === "counted");
  const rows = [];

  for (const caseId of [...new Set(counted.map((record) => record.caseId))]) {
    const group = counted.filter((record) => record.caseId === caseId);

    rows.push([
      caseId,
      seconds(median(group.map((record) => record.real))),
      seconds(Math.min(...group.map((record) => record.real))),
      seconds(median(group.map((record) => record.cpuSec))),
      `${Math.round(median(group.map((record) => record.cpuPct)))}%`,
      group.every((record) => record.status === "pass") ? "pass" : "fail",
      group.length,
    ]);
  }

  return renderBoxTable(
    ["Cmd", "Median Real", "Min Real", "Median CPU sec", "Median CPU%", "Status", "Counted Runs"],
    rows,
  );
}

function renderSamples(rows) {
  return renderBoxTable(
    ["Run", "Real", "User", "Sys", "CPU sec", "CPU%", "Status", "Tests", "Fail"],
    rows.map((record) => [
      record.phase === "warmup" ? `warmup ${record.run}` : String(record.run),
      seconds(record.real),
      seconds(record.user),
      seconds(record.sys),
      seconds(record.cpuSec),
      `${Math.round(record.cpuPct)}%`,
      record.status,
      record.tests,
      record.fail,
    ]),
  );
}

function renderBoxTable(headers, rows) {
  const table = [headers, ...rows.map((row) => row.map(String))];
  const widths = headers.map((_, column) =>
    Math.max(...table.map((row) => row[column].length)),
  );
  const border = `+${widths.map((width) => "-".repeat(width + 2)).join("+")}+`;

  return [
    border,
    renderBoxRow(headers, widths),
    border,
    ...rows.map((row) =>renderBoxRow(row, widths)),
    border,
  ].join("\n");
}

function renderBoxRow(row, widths) {
  return`| ${row
    .map((cell, column) => String(cell).padEnd(widths[column]))
    .join(" | ")} |`;
}

async function collectEnvironmentSnapshot() {
  const rows = [
    ["date", "ok", runDate],
    ["timestamp", "ok", startedAt],
    ["profile", "ok", profile],
    ["output", "ok", outFile],
    ["host", "ok", os.hostname()],
    ["platform", "ok", `${process.platform} ${process.arch}`],
    ["logical cpus", "ok", String(os.cpus().length)],
  ];

  const commands = [
    ["git rev-parse --short HEAD", "git rev-parse --short HEAD"],
    ["git status --short", "git status --short"],
    ["node --version", "node --version"],
    ["package manager version", readOption("--package-manager-version-cmd", "pnpm --version")],
    ["compiler version", readOption("--compiler-version-cmd", "pnpm exec tsc --version")],
    ["uptime", "uptime"],
  ];

  for (const [key, command] of commands) {
    const result = await captureCommand(command);
    rows.push([key, result.status, compact(result.value)]);
  }

  return rows;
}

function extractTestStats(text) {
  return {
    tests: findNumber(text, [
      /^tests:\s*(\d+)/gim,
      /^#\s*tests\s+(\d+)/gim,
      /(\d+)\s+tests?/gim,
    ]),
    fail: findNumber(text, [
      /^fail:\s*(\d+)/gim,
      /^#\s*fail\s+(\d+)/gim,
      /(\d+)\s+fail(?:ed|ures?)?/gim,
    ]),
  };
}

function findNumber(text, patterns) {
  for (const pattern of patterns) {
    const match = [...text.matchAll(pattern)].at(-1);

    if (match?.[1] !== undefined) {
      return match[1];
    }
  }

  return undefined;
}

async function captureCommand(command) {
  return new Promise((resolve) => {
    const child = spawn(shellBin, ["-c", command], {
      stdio: ["ignore", "pipe", "pipe"],
    });

    let stdout = "";
    let stderr = "";

    child.stdout.on("data", (chunk) => {
      stdout += chunk;
    });

    child.stderr.on("data", (chunk) => {
      stderr += chunk;
    });

    child.on("close", (exitCode) => {
      resolve({
        status: exitCode === 0 ? "ok" : `fail:${exitCode}`,
        value: stdout.trim() || stderr.trim() || "n/a",
      });
    });
  });
}

function heading(text) {
  return `${text}\n${"-".repeat(text.length)}`;
}

function compact(value, maxLength = 180) {
  const normalized = value.replace(/\s*\n\s*/g, " / ").trim();
  return normalized.length > maxLength
    ? `${normalized.slice(0, maxLength - 3)}...`
    : normalized;
}

function median(values) {
  const sorted = [...values].sort((left, right) => left - right);
  const middle = Math.floor(sorted.length / 2);

  if (sorted.length % 2 === 1) {
    return sorted[middle];
  }

  return (sorted[middle - 1] + sorted[middle]) / 2;
}

function seconds(value) {
  return`${value.toFixed(2)}s`;
}

function numberOption(name, fallback) {
  const value = readOption(name);
  return value === undefined ? fallback : Number(value);
}

functionreadOption(name, fallback = undefined) {
  const index = process.argv.indexOf(name);
  return index === -1 ? fallback : process.argv[index + 1];
}

附录 B:记录文件节选

附录 B 放的是当时真实生成的 .txt 记录,不是二次整理后的摘要。节选保留原文件里的命令、采样、CPU、测试结果和环境信息,方便回看数据来源。这里截到第一次 C1 / C2 完整记录,并带上后一轮 stable batch 的开头;后面还有多轮追加测评,末尾用截断标记说明。

TypeScript Compile / Check Speed Baseline
=========================================

Recorded at : 2026-07-09
Repo        : /Users/lencx/github/noi-workspace/noi-next
Compiler    : TypeScript 6.0.3
Package mgr : pnpm 11.9.0, from package.json packageManager field
Purpose     : Baseline before evaluating a TypeScript 7 upgrade.

CPU formula : cpu_seconds = user + sys
              cpu_percent ~= (user + sys) / real * 100
              Values over 100% mean multiple CPU cores were used.

Command Keys
------------

+------+------------------------------------------------+
| Key  | Command                                        |
+------+------------------------------------------------+
| C1   | pnpm exec tsc --noEmit --pretty false          |
| C2   | pnpm typecheck --full                         |
+------+------------------------------------------------+

Summary
-------

+-------------------------+-------------+---------+----------+------------------------------------------+
| Measure                 | Wall Time   | Status  | CPU%     | Notes                                    |
+-------------------------+-------------+---------+----------+------------------------------------------+
| C1 typical              | ~4.9s       | pass    | ~174%    | Three normal runs: 4.85s, 4.35s, 4.94s  |
| C1 outlier              | 28.11s      | pass    | ~67%     | Likely machine load / cache noise        |
| C2 full gate            | 49.71s      | pass    | ~1371%   | Non-sandbox CPU sample; 2239 passed      |
| C2 earlier full gate    | ~51.6s      | pass    | n/a      | Non-sandbox run; kernel reported 48.66s  |
| C2 full gate in sandbox | 51.86s      | fail    | ~1337%   | Blocked by listen EPERM on 127.0.0.1     |
+-------------------------+-------------+---------+----------+------------------------------------------+

C1: tsc --noEmit Samples
------------------------

+-----+--------+--------+-------+---------+-------+--------+-------------------------------+
| Run | Real   | User   | Sys   | CPU sec | CPU%  | Status | Note                          |
+-----+--------+--------+-------+---------+-------+--------+-------------------------------+
| 1   | 4.85s  | 7.93s  | 0.34s | 8.27s   | 171%  | pass   | Initial baseline sample       |
| 2   | 4.35s  | 7.34s  | 0.26s | 7.60s   | 175%  | pass   | Normal sample                 |
| 3   | 28.11s | 18.22s | 0.64s | 18.86s  | 67%   | pass   | Outlier; do not use as normal |
| 4   | 4.94s  | 8.39s  | 0.34s | 8.73s   | 177%  | pass   | Normal sample                 |
+-----+--------+--------+-------+---------+-------+--------+-------------------------------+

Usable C1 baseline: about 4.9s wall time and about 174% CPU.

C2: Full Typecheck Gate
-----------------------

+-------------+-----------+--------+-------+---------+-------+---------+--------------+----------------------------+
| Environment | Real      | User   | Sys   | CPU sec | CPU%  | Status  | Test Result  | Notes                      |
+-------------+-----------+--------+-------+---------+-------+---------+--------------+----------------------------+
| non-sandbox | 49.71s    | 640.13 | 41.25 | 681.38  | 1371% | pass    | 2239 passed  | CPU sample run             |
| non-sandbox | ~51.6s    | n/a    | n/a   | n/a     | n/a   | pass    | 2225 passed  | Earlier wall-only run      |
| sandbox     | 51.86s    | 646.87 | 46.59 | 693.46  | 1337% | fail    | 2220/2225    | 5 localhost EPERM failures |
+-------------+-----------+--------+-------+---------+-------+---------+--------------+----------------------------+

Kernel test report from the passing non-sandbox C2 CPU sample:

+-------------+----------+
| Field       | Value    |
+-------------+----------+
| tests       | 2239     |
| pass        | 2239     |
| fail        | 0        |
| duration_ms | 42374.08 |
+-------------+----------+

Kernel test report from the earlier passing non-sandbox C2 run:

+-------------+----------+
| Field       | Value    |
+-------------+----------+
| tests       | 2225     |
| pass        | 2225     |
| fail        | 0        |
| duration_ms | 48661.19 |
+-------------+----------+

Notes
-----

+----+-----------------------------------------------------------------------+
| #  | Note                                                                  |
+----+-----------------------------------------------------------------------+
| 1  | Use the non-sandbox C2 number when comparing full gate speed.           |
| 2  | The sandbox C2 failure is environmental: mobile tests listen on         |
|    | 127.0.0.1 and hit EPERM under the sandbox.                              |
| 3  | Compare TypeScript 7 against C1 wall/CPU and C2 wall/CPU.                |
| 4  | CPU% is approximate and machine-load-sensitive; compare repeated runs.   |
| 5  | If future C1 runs vary heavily, collect at least 3 normal samples.       |
+----+-----------------------------------------------------------------------+

Stable TS6 vs TS7 Comparison Protocol
-------------------------------------

This baseline is enough for rough comparison. For a stable, defensible TS7
comparison, collect repeated samples under the same protocol below.

+------+---------------------------------------------------------------------+
| Step | Rule                                                                |
+------+---------------------------------------------------------------------+
| 1    | Use the same machine, power mode, repo, Node, pnpm, and working set.  |
| 2    | Close heavyweight apps and stop dev servers before measurement.       |
| 3    | Record environment and top CPU processes before each batch.           |
| 4    | Run one warm-up per command and do not count it.                      |
| 5    | Run C1 at least 5 counted times for each compiler.                    |
| 6    | Run C2 at least 3 counted times for each compiler if time allows.     |
| 7    | Compare median wall time as the main developer-wait metric.           |
| 8    | Compare min wall time as the low-interference best-case metric.       |
| 9    | Compare CPU sec and CPU% to separate efficiency from parallelism.     |
| 10   | Do not compare C2 runs as equivalent if test counts differ materially.|
+------+---------------------------------------------------------------------+

Environment Snapshot To Record
------------------------------

+------+---------------------------------------------------------------+
| Key  | Command / Value                                                |
+------+---------------------------------------------------------------+
| E1   | date                                                          |
| E2   | git rev-parse --short HEAD                                    |
| E3   | git status --short                                            |
| E4   | node --version                                                |
| E5   | pnpm --version                                                |
| E6   | pnpm exec tsc --version                                       |
| E7   | uptime                                                        |
| E8   | sysctl -n hw.logicalcpu hw.physicalcpu machdep.cpu.brand_string|
| E9   | pmset -g batt                                                 |
| E10  | pmset -g therm                                                |
| E11  | ps -axo pid,pcpu,pmem,comm                                    |
+------+---------------------------------------------------------------+

For E11, keep the top CPU consumers in the comparison note. The exact terminal
pipeline can vary; the important part is recording unexpected background load.

Comparison Calculations
-----------------------

+---------------------+-----------------------------------------------------+
| Metric              | Formula                                             |
+---------------------+-----------------------------------------------------+
| wall speedup        | TS6 median real / TS7 median real                   |
| wall change percent | (TS7 median real - TS6 median real) / TS6 * 100     |
| CPU sec             | user + sys                                          |
| CPU sec change      | (TS7 CPU sec - TS6 CPU sec) / TS6 CPU sec * 100     |
| CPU percent         | (user + sys) / real * 100                           |
+---------------------+-----------------------------------------------------+

Interpretation:

+------------------------------+------------------------------------------------------+
| Shape                        | Meaning                                              |
+------------------------------+------------------------------------------------------+
| Lower wall, lower CPU sec    | Faster and more CPU-efficient.                       |
| Lower wall, higher CPU sec   | Faster by using more parallel CPU.                   |
| Same wall, lower CPU sec     | Similar wait time, lower machine pressure.           |
| Lower wall, same test count  | Valid speedup signal.                                |
| Lower wall, changed tests    | Not directly comparable without explaining the delta.|
+------------------------------+------------------------------------------------------+

Recommended TS7 Result Table
----------------------------

+----------+----------+---------+-------+---------+-------+---------+------------+
| Compiler | Command  | Real    | User  | Sys     | CPU%  | Status  | Test Count |
+----------+----------+---------+-------+---------+-------+---------+------------+
| TS6      | C1 median|         |       |         |       |         | n/a        |
| TS7      | C1 median|         |       |         |       |         | n/a        |
| TS6      | C2 median|         |       |         |       |         |            |
| TS7      | C2 median|         |       |         |       |         |            |
+----------+----------+---------+-------+---------+-------+---------+------------+

TS6 Stable Batch 2026-07-09T01:19:35.622Z
=========================================

Run kind    : Restarted TS6 stable comparison batch
Compiler    : Version 6.0.3
Node        : v26.3.0
pnpm        : 11.7.0
Host        : lencx-MacBook-Pro.local

Batch Summary
-------------

+-----+-------------+----------+----------------+-------------+--------+--------------+
| Cmd | Median Real | Min Real | Median CPU sec | Median CPU% | Status | Counted Runs |
+-----+-------------+----------+----------------+-------------+--------+--------------+
| C1  | 4.39s       | 4.19s    | 7.70s          | 175%        | pass   | 5            |
| C2  | 78.30s      | 61.50s   | 1002.25s       | 1280%       | pass   | 3            |
+-----+-------------+----------+----------------+-------------+--------+--------------+

[... 后续多轮 TS6 / TS7 追加测评记录已截断,完整文件保留原始连续追加内容。]

References

[1]

esbuild:https://esbuild.github.io

[2]

VoidZero:https://voidzero.dev

[3]

Bun:https://bun.com

[4]

Turborepo:https://turborepo.dev

[5]

uv:https://docs.astral.sh/uv/

[6]

Ruff:https://docs.astral.sh/ruff/

[7]

Announcing TypeScript 7.0:https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/

文章标签AI资讯
资讯来源:由AI资讯编辑整理自互联网公开内容,版权归原作者所有,未经许可,不得转载。

继续浏览更多资讯

返回资讯目录

相关资讯

更多