plugins/languages/typescript/skills/core/SKILL.md
TypeScript / JavaScript 核心开发规范,TS 6.0+ 严格模式优先,覆盖 tsconfig、Biome 2 / ESLint flat、pnpm 10 / Bun / Deno 2、Node 22-24 LTS、Vite 6 + Rolldown、Vitest 3、Zod 4。同时给出 JS-only 项目的 JSDoc + tsc --checkJs 兜底路径。Use when 新建 TS/JS 项目、配置 tsconfig、设置 linter/formatter、迁移 ESM、选型工具链,或用户提到 "TypeScript 规范"、"JS 规范"、"strict mode"、"tsconfig"、"biome"、"eslint"、"ESM"、"package manager"、"ES2025"。
npx skillsauth add lazygophers/ccplugin typescript-coreInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
本 skill 同时覆盖 JavaScript 项目;TypeScript 为首选,JS-only 写法见各节末尾兜底说明。
适用范围:所有 .ts / .tsx / .mts / .cts / .js / .jsx 源码。
类型安全 > 类型体操;编译期错误 > 运行期错误;显式 > 隐式。
strict: true + noUncheckedIndexedAccess + noImplicitOverride + exactOptionalPropertyTypesany — 用 unknown + 类型守卫,或 Zod 4 / Valibot 在边界验证"type": "module" + TS 用 import type 分离类型导入const 优先, let 次之, 禁 var.toSorted() / .toReversed() / .with() / structuredClone()any、@ts-ignore、enum (用 as const 对象代替)、namespacevar、require() / module.exports (ESM only)if (err) return err).eslintrc.js (旧) → flat config 或 Biomenode-fetch (Node 22+ 已内置 fetch)React.FC (隐式 children、泛型受限)console.log (用 pino 9 / console.warn / console.error)| 项 | 推荐 | 说明 |
|----|------|------|
| TypeScript | 6.0 稳定 | target: ES2025,strict 默认开 |
| TS 7.0 / tsgo | CI type-check 可用 | Go 重写 10x;emit 未 GA;用 @typescript/native-preview |
| 语言 | ES2025 + ES2026 stage 3+ | 兼容 ES2024 |
| Node.js | 22 LTS / 24 Active LTS | 原生 strip-types (22.18+)、原生 fetch、test runner |
| 运行时 | Node 22-24 / Bun 1.x / Deno 2 | 三选一 |
| 包管理 | pnpm 10 / Bun 1.x | 禁 npm 新项目 |
| Linter+Formatter | Biome 2 优先 / ESLint 9 flat (重 plugin 时) | Biome 2.3+ 423 规则 + 部分类型感知 |
| 测试 | Vitest 3.x | bench、type 测试、ESM 原生 |
| 构建 | Vite 6 (Rolldown) / tsdown / tsup | 库优先 tsdown |
| HTTP 框架 | Hono 4 / Fastify 5 | Express 5 (legacy) |
| 校验 | Zod 4 | Valibot / ArkType (小 bundle) |
{
"compilerOptions": {
"target": "ES2025",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2025"],
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noFallthroughCasesInSwitch": true,
"exactOptionalPropertyTypes": true,
"verbatimModuleSyntax": true,
"isolatedModules": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"declaration": true,
"sourceMap": true,
"outDir": "./dist"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
// ES2025 - Iterator helpers
const evens = arr.values().filter(x => x % 2 === 0).take(10).toArray();
// ES2025 - Set methods
const u = a.union(b); const i = a.intersection(b); const d = a.difference(b);
// ES2025 - Object.groupBy / Map.groupBy
const byRole = Object.groupBy(users, u => u.role);
// ES2025 - Promise.try (同步异常进 Promise 链)
const p = Promise.try(() => mayThrowSync());
// ES2024 - Promise.withResolvers
const { promise, resolve, reject } = Promise.withResolvers();
// ES2025 - Array.fromAsync
const items = await Array.fromAsync(asyncIterable);
// ES2025 - RegExp /v flag
const re = /[\p{Emoji}--\p{ASCII}]/v;
// ES2026 stage 3 - using / await using
{
using file = openFile('data.txt');
await using db = await connectDB();
}
// Temporal (stage 3) - 替代 Date / moment
const now = Temporal.Now.zonedDateTimeISO();
// biome.json
{
"$schema": "https://biomejs.dev/schemas/2.3.0/schema.json",
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"style": { "noVar": "error", "useConst": "error" },
"suspicious": { "noConsole": "warn" }
}
},
"formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2, "lineWidth": 100 },
"javascript": { "formatter": { "quoteStyle": "double", "semicolons": "always" } }
}
pnpm dlx @biomejs/biome init
pnpm biome check --write . # lint + format 一把梭
// eslint.config.ts (TS 项目)
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.strictTypeChecked,
{
languageOptions: {
parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname },
},
rules: {
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/consistent-type-imports": ["error", { prefer: "type-imports" }],
},
},
);
type UserDTO = { id: string }; // 类型 PascalCase (禁 I 前缀)
type Status = "active" | "inactive";
const userName = "John"; // 变量 camelCase
function getUserById(id: string) { /* ... */ } // 函数 camelCase
const MAX_RETRIES = 3; // 常量 UPPER_SNAKE_CASE
// 文件 kebab-case: user-service.ts
// as const 替代 enum
const Role = { Admin: "admin", User: "user" } as const;
type Role = (typeof Role)[keyof typeof Role];
pnpm add -D @typescript/native-preview
pnpm exec tsgo --noEmit # CI 快速类型检查
# 注意:emit/decorators/older targets 尚未完整,构建仍用 tsc
若项目暂不切 TS,仍可获得 80% 类型保护:
// package.json
{ "type": "module" }
// jsconfig.json (或 tsconfig.json with allowJs)
{
"compilerOptions": {
"target": "ES2025",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"allowJs": true,
"checkJs": true, // 对 .js 也跑类型检查
"strict": true,
"noEmit": true,
"skipLibCheck": true
},
"include": ["src/**/*"]
}
// 用 JSDoc 标注类型,tsc 当 linter 用
/**
* @typedef {{ id: string; name: string; email: string }} User
*/
/**
* @param {string} id
* @returns {Promise<User>}
*/
export async function getUser(id) {
const r = await fetch(`/api/users/${id}`);
if (!r.ok) throw new Error(`HTTP ${r.status}`);
return /** @type {User} */ (await r.json());
}
# 类型检查 (零编译产物)
pnpm tsc --noEmit
Biome 2 / ESLint flat 对 JS 项目同样有效;JS 项目把上面 ESLint 示例去掉 tseslint,仅用 @eslint/js:
// eslint.config.js
import js from '@eslint/js';
export default [
js.configs.recommended,
{
files: ['src/**/*.{js,jsx}'],
rules: {
'no-var': 'error',
'prefer-const': 'error',
'no-console': ['warn', { allow: ['warn', 'error'] }],
},
},
];
迁移路线:JSDoc + checkJs → 文件级 .ts → 局部启 strict → 全量 strict。
| 现象 | 问题 | 严重 |
|------|------|------|
| any | 类型安全漏洞 | 高 |
| @ts-ignore | 隐藏真实错误 (用 @ts-expect-error + 注释) | 高 |
| var / require() | ESM / const / let | 高 |
| enum | tree-shaking 不友好 | 中 |
| .eslintrc.js | 旧 schema | 中 |
| 文件 > 500 行 | 拆分信号 | 中 |
| npm install 新项目 | pnpm/Bun 更优 | 中 |
| Jest 配置 | Vitest 3.x 替代 | 中 |
| 生产 console.log | pino 结构化输出 | 中 |
| 无运行时校验 | Zod 4 边界校验 | 高 |
| arr.sort() 变异 | arr.toSorted() | 中 |
strict: true + noUncheckedIndexedAccess + exactOptionalPropertyTypesany / @ts-ignore;JS: JSDoc + checkJs: trueas const 替代 enumimport type 分离类型导入"type": "module",ESM onlyconst/let,无 vardevelopment
Go 数据库规范——GORM Model 命名 ModelXxx、表名单数、枚举 uint8 + 常量、索引 idx_ 前缀 + deleted_at leading column、禁 time.Time 统一 int64 unix、禁指针/nullable 字段、TEXT/BLOB/JSON 禁 default、AutoMigrate 禁改主键。设计 DB model、写 GORM tag、建索引、做 migration 审查时触发。
development
Go HTTP API 规范——响应始终 200 + body code 字段、路由 /api/* 全 POST 单段 <Action><Model>、中间件逐路由注册禁 Group(prefix,mw...)、handler 仅返回 (rsp,error)、认证走 header。设计 HTTP API、写路由/handler/中间件时触发。
development
Go 项目结构规范——三层架构(API → Impl → State)、全局状态模式、internal/ 私有包、cmd/ 仅 main.go、go.work 多模块、禁止 Repository 接口和 DI 容器、struct 公共字段开头全 omitempty、handler var rsp 顶声明、禁 legacy migration。设计项目骨架、新建目录、组织包、做架构评审时触发。
development
Go 命名规范——Id/Uid 字段(非 ID)、IsActive/HasMFA 布尔前缀、CreatedAt 时间字段、接收者统一用 p、包名全小写无下划线、泛型类型参数描述性命名、集合字段 xxx_list 禁 xxxs 复数、Enum 0 值 XxxNil 禁 Unknown、禁 Status 统一 State、Set/Update 语义区分。定义结构体字段、函数、变量、包、接收者名、泛型、枚举时触发。