决定代码生成速度的不只是模型,还应包括各种开发基建!
TypeScript 7 已经可以正式安装和使用。对只跑 tsc 的项目,它接近一次直接版本升级;对真实工程,它更像一次工具链边界重排。
我的体感很直接:把本地项目从 TS6 切到 TS7 后,再跑全量类型检查,机器没有再进入风扇明显起转的高压状态(完全静音了)。这个感受和后面的测评数据一致:纯 tsc 从 4.38s 降到 0.60s,完整本地 gate 从 54.92s 降到 27.23s。对配置更低、散热更保守的机器来说,这类升级带来的收益不只是少等几秒,也可能是更低的发热、噪声和电量压力。

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,把
pip、pip-tools、pipx、poetry、pyenv、virtualenv等路径收敛到一个工具;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
需要修的是工具链入口:
- 依赖
createProgram、transpileModule或 AST 类型信息的路径,继续走 TS6 alias。 - TypeScript 脚本执行从
ts-node/register/transpile-only迁到tsx。 - 只做片段转译或语法结构判断的脚本,改成更轻路径,不再默认加载完整
typescript。 tsconfig清理 TS7 已推到硬错误边界的旧配置,例如旧的moduleResolution、module、baseUrl、ignoreDeprecations。
这样拆完以后,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
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/







