【TraeCode上手记】用 TraeCode 从零写了个 TypeScript CLI,脚手架和边界坑都替你踩了一遍

我之前主要写 Node.js + TypeScript 的后端接口和命令行脚本,但每次起一个新的 CLI 项目都很烦:要手写 commander 参数解析、调 tsconfig 的 module/target、配 package.json 的 bin 字段,还要搞定构建后的 require 路径。上周我试着用 TraeCode 从零写一个「API 存活巡检」小工具——定时 ping 一组 HTTP 接口,超时的打到控制台和本地 json 日志里。整个过程比我想的顺,也踩了几个实打实的坑。

这次想解决什么

公司里有几个对外接口,之前靠人肉盯监控面板,偶尔某条挂了要半天才发现。我想做个命令行工具,一条命令跑起来,定时批量请求接口,超过阈值就告警。工具本身不复杂,难的是"把脚手架那一堆配置做对"——这正是我最烦、也最容易出问题的地方。

我是谁,为什么现在试

算是有 Node/TS 经验的老手了,不是第一次学编程。所以我想看的不是"AI 能不能写代码",而是"这件我干过很多遍、但又繁琐的事,能不能更快"——尤其是脚手架配置和类型定义这块。

怎么慢慢用顺的

我第一句直接描述需求:“用 TypeScript 写一个 CLI 工具,支持 -u 传入多个地址、-i 传间隔秒数、超时阈值,结果打控制台和 json 日志”。TraeCode 一口气生成了完整项目结构,commander、tsconfig、bin 字段都配好了,能直接跑。这比我预想强——以前脚手架我得自己抄。真正值的是后面的追问,几个坑都点到了位置上:

第一个坑是运行环境。我一开始想用 node-fetch,TraeCode 给的代码里 import fetch from 'node-fetch',运行时却报 fetch is not a function。跟它说明了目标环境是 Node 20,它直接建议我改用内置的全局 fetch(Node 18+ 自带),把 node-fetch 这个依赖和它的类型包都省了。少一个依赖、少一份类型冲突,这个建议很实在。

第二个坑是并发和超时。一开始用 for 循环串行请求,接口一多巡检一轮要等很久。让它改成 Promise.allSettled 并发,同时每个请求加 AbortController 超时:

async function checkOne(url: string, timeoutMs: number) {
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeoutMs);
  try {
    const res = await fetch(url, { signal: controller.signal });
    return { url, ok: res.ok, status: res.status };
  } catch (e) {
    return { url, ok: false, status: 0, error: String(e) };
  } finally {
    clearTimeout(timer);
  }
}

allSettled 的好处是单个接口超时不会拖垮整轮,这个写法我本来也会,但 TraeCode 直接把 abort 后的定时器清理都补全了,不用我自己记着加。

第三个坑是写日志时目录不存在。往 logs/ 写文件,目录没建会直接抛错,它一开始也没处理。我点了一句,它补上 fs.mkdirSync(dir, { recursive: true })。这种边界它不会主动想到,但你提出来它秒修。

最后做成了什么,给后来的人一句建议

工具半天时间从零跑到能上线:一条命令定时巡检十几个接口,超时告警 + json 日志落盘。省的是脚手架和告警代码的反复搬运。

给后来的人一句实在话:别把它当"一句话出成品"的许愿机,把它当一个"懂业务但偶尔漏边界的老搭档"——需求说清楚,运行环境(Node 版本、依赖版本)主动报,踩到边界立刻追一句,它改得又快又准。它真正帮你省的时间,是省在那些你早就懂、但懒得再写一遍的样板代码上。

2 个赞