From typescript
TypeScript Node.js 后端开发规范,覆盖 Node.js 22 LTS、ESM 模块系统、native fetch、fs/promises 文件操作与 native test runner 测试。适用于开发 Node.js 服务端应用、CLI 工具、API 服务时加载。
npx claudepluginhub lazygophers/ccplugin --plugin typescriptThis skill uses the workspace's default tool permissions.
| Agent | 说明 |
Provides Ktor server patterns for routing DSL, plugins (auth, CORS, serialization), Koin DI, WebSockets, services, and testApplication testing.
Conducts multi-source web research with firecrawl and exa MCPs: searches, scrapes pages, synthesizes cited reports. For deep dives, competitive analysis, tech evaluations, or due diligence.
Provides demand forecasting, safety stock optimization, replenishment planning, and promotional lift estimation for multi-location retailers managing 300-800 SKUs.
| Agent | 说明 |
|---|---|
| dev | TypeScript 开发专家 |
| test | TypeScript 测试专家 |
| perf | TypeScript 性能优化专家 |
| 场景 | Skill | 说明 |
|---|---|---|
| 核心规范 | Skills(core) | TS 5.7+、strict mode |
| 类型系统 | Skills(types) | Zod schema、类型安全 API |
| 异步编程 | Skills(async) | Promise、streams、async iterators |
| 安全编码 | Skills(security) | 输入验证、依赖审计 |
node --test(轻量场景)fs.glob()(实验性)// package.json
{ "type": "module" }
// tsconfig.json
{
"compilerOptions": {
"target": "ES2024",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"verbatimModuleSyntax": true
}
}
// ESM 导入
import { readFile, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
// ESM 中获取 __dirname
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// 或使用 import.meta.dirname (Node.js 21.2+)
const dir = import.meta.dirname;
import { readFile, writeFile, mkdir, readdir, stat } from "node:fs/promises";
// 读取文件
async function loadConfig(configPath: string): Promise<Config> {
const content = await readFile(configPath, "utf-8");
const data: unknown = JSON.parse(content);
return ConfigSchema.parse(data); // Zod 验证
}
// 写入文件(确保目录存在)
async function saveData(filePath: string, data: unknown): Promise<void> {
await mkdir(path.dirname(filePath), { recursive: true });
await writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
}
// 递归遍历目录
async function* walkDir(dir: string): AsyncGenerator<string> {
const entries = await readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
yield* walkDir(fullPath);
} else {
yield fullPath;
}
}
}
// GET 请求
async function getUser(id: string): Promise<User> {
const response = await fetch(`https://api.example.com/users/${id}`, {
headers: { "Content-Type": "application/json" },
signal: AbortSignal.timeout(5000), // Node.js 22 内置超时
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data: unknown = await response.json();
return UserSchema.parse(data);
}
// POST 请求
async function createUser(user: CreateUserInput): Promise<User> {
const response = await fetch("https://api.example.com/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(user),
});
if (!response.ok) {
const error: unknown = await response.json();
throw new Error(`Create failed: ${JSON.stringify(error)}`);
}
return UserSchema.parse(await response.json());
}
import { createReadStream, createWriteStream } from "node:fs";
import { pipeline } from "node:stream/promises";
import { Transform } from "node:stream";
// 大文件流处理
async function processLargeFile(inputPath: string, outputPath: string): Promise<void> {
const transform = new Transform({
transform(chunk: Buffer, _encoding, callback) {
const processed = chunk.toString("utf-8").toUpperCase();
callback(null, processed);
},
});
await pipeline(
createReadStream(inputPath, "utf-8"),
transform,
createWriteStream(outputPath),
);
}
// 异步迭代器消费 stream
async function readLines(filePath: string): Promise<string[]> {
const content = await readFile(filePath, "utf-8");
return content.split("\n").filter(Boolean);
}
import { Worker, isMainThread, parentPort, workerData } from "node:worker_threads";
// 主线程
function runWorker<T, R>(workerPath: string, data: T): Promise<R> {
return new Promise((resolve, reject) => {
const worker = new Worker(workerPath, { workerData: data });
worker.on("message", resolve);
worker.on("error", reject);
worker.on("exit", (code) => {
if (code !== 0) reject(new Error(`Worker exited with code ${code}`));
});
});
}
// Worker 文件
if (!isMainThread && parentPort) {
const result = heavyComputation(workerData);
parentPort.postMessage(result);
}
import { z } from "zod";
const EnvSchema = z.object({
NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
PORT: z.coerce.number().int().min(1).max(65535).default(3000),
DATABASE_URL: z.string().url(),
API_KEY: z.string().min(32),
LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
});
export const env = EnvSchema.parse(process.env);
import { Hono } from "hono";
import { zValidator } from "@hono/zod-validator";
const app = new Hono();
app.get("/api/users/:id", async (c) => {
const id = c.req.param("id");
const user = await db.user.findUnique({ where: { id } });
if (!user) return c.json({ error: "Not found" }, 404);
return c.json(user);
});
app.post("/api/users",
zValidator("json", CreateUserSchema),
async (c) => {
const data = c.req.valid("json");
const user = await db.user.create({ data });
return c.json(user, 201);
},
);
export default app;
| 现象 | 问题 | 严重程度 |
|---|---|---|
require() 导入 | 应使用 ESM import | 高 |
fs.readFileSync | 应使用 fs/promises | 中 |
node-fetch 包 | Node.js 22 有 native fetch | 低 |
__dirname(CJS) | ESM 中使用 import.meta.dirname | 中 |
| 无环境变量验证 | 应使用 Zod 验证 process.env | 高 |
| Express(新项目) | 考虑 Hono / Fastify 替代 | 低 |
"type": "module" 在 package.jsonmodule: "NodeNext" 在 tsconfig.jsonnode: 前缀导入内置模块fs/promises(非 sync API)