Help us improve
Share bugs, ideas, or general feedback.
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 typescriptHow this skill is triggered — by the user, by Claude, or both
Slash command
/typescript:nodejssonnetThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
| Agent | 说明 |
Node.js development principles and decision-making. Framework selection, async patterns, security, and architecture. Teaches thinking, not copying.
Guides Node.js decisions on framework selection (Hono, Fastify, Express, NestJS), async patterns, layered architecture, security, runtime choices (Bun, Deno), and deployment.
Share bugs, ideas, or general feedback.
| 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)