关于 typescript-quality
面向开发者的 TypeScript 代码质量速查技能,涵盖 lint、格式化、严格类型检查和提交前工作流配置,并比较 Biome 与 ESLint,提供配置和排障指引。
主要功能
- 01Biome 与 ESLint 配置指南
- 02TypeScript 严格模式配置
- 03代码异味与反模式示例
- 04使用 Husky 和 lint-staged 进行提交前检查
- 05排障说明与质量指标
适用场景
- 01为 TypeScript 项目选择 lint 工具
- 02启用更严格的编译器检查
- 03设置提交前代码检查
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ claude-dev-suite/ claude-dev-suite --skill typescript-quality安装后在 Claude Code 中输入/typescript-quality确认已加载。
详细介绍
TypeScript 代码质量 - 快速参考
不适合使用此技能的情况
- SonarQube 集成 - 使用
sonarqube技能 - 测试配置 - 使用
vitest技能 - 安全扫描 - 使用安全技能
- React 专属模式 - 使用
react技能
深入了解:使用
mcp__documentation__fetch_docs,并将 technology 设为typescript或biome,以获取全面的文档。
工具对比
| 工具 | 速度 | 类型感知 | 配置 |
|---|---|---|---|
| Biome | 最快 | 否 | 最少 |
| ESLint | 较慢 | 是(配合 TS) | 丰富 |
| TypeScript | 不适用 | 是 | tsconfig.json |
建议:使用 Biome 进行格式化和基础 lint,使用 ESLint 检查类型感知规则。
Biome 设置(推荐)
安装
npm install -D @biomejs/biome
npx biome init
biome.json
{
"$schema": "https://biomejs.dev/schemas/1.9.0/schema.json",
"organizeImports": { "enabled": true },
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"complexity": {
"noExcessiveCognitiveComplexity": {
"level": "warn",
"options": { "maxAllowedComplexity": 15 }
}
},
"suspicious": {
"noExplicitAny": "error",
"noImplicitAnyLet": "error"
},
"style": {
"noNonNullAssertion": "warn",
"useConst": "error"
}
}
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"trailingCommas": "es5",
"semicolons": "always"
}
}
}
命令
# Check all
npx biome check .
# Fix auto-fixable
npx biome check --write .
# Format only
npx biome format --write .
# Lint only
npx biome lint .
# CI mode (no write)
npx biome ci .
ESLint 设置(类型感知)
安装
npm install -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
eslint.config.js(Flat Config - ESLint 9+)
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.stylisticTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
// Type safety
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
// Best practices
'@typescript-eslint/explicit-function-return-type': 'warn',
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/no-misused-promises': 'error',
// Code quality
'complexity': ['warn', { max: 10 }],
'max-depth': ['warn', { max: 4 }],
'max-lines-per-function': ['warn', { max: 50 }],
},
},
{
ignores: ['dist/', 'node_modules/', '*.config.js'],
}
);
命令
# Lint
npx eslint .
# Fix auto-fixable
npx eslint --fix .
# Show rule details
npx eslint --print-config src/index.ts
TypeScript 严格模式
tsconfig.json(最高严格度)
{
"compilerOptions": {
// Strict type checking
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"noPropertyAccessFromIndexSignature": true,
// Additional checks
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
// Module resolution
"moduleResolution": "bundler",
"module": "ESNext",
"target": "ES2022",
// Interop
"esModuleInterop": true,
"isolatedModules": true,
"verbatimModuleSyntax": true
}
}
关键严格标志说明
| 标志 | 效果 | 示例 |
|---|---|---|
noUncheckedIndexedAccess | 数组访问返回 T | undefined | arr[0] 的类型为 T | undefined |
exactOptionalPropertyTypes | { a?: string } 表示字符串或缺失,而不是 undefined | 不能显式赋值为 undefined |
noPropertyAccessFromIndexSignature | 索引签名必须使用方括号表示法 | 使用 obj['key'],而不是 obj.key |
常见代码异味及修复方法
1. 过度使用 any
// BAD
function process(data: any): any {
return data.value;
}
// GOOD
interface DataItem {
value: string;
}
function process(data: DataItem): string {
return data.value;
}
// GOOD - When truly unknown
function process(data: unknown): string {
if (typeof data === 'object' && data !== null && 'value' in data) {
return String((data as { value: unknown }).value);
}
throw new Error('Invalid data');
}
2. 过度使用类型断言
// BAD
const user = response.data as User;
// GOOD - Use type guards
function isUser(data: unknown): data is User {
return (
typeof data === 'object' &&
data !== null &&
'id' in data &&
'email' in data
);
}
if (isUser(response.data)) {
// response.data is User here
}
// GOOD - Use Zod for runtime validation
import { z } from 'zod';
const UserSchema = z.object({
id: z.string(),
email: z.string().email(),
});
const user = UserSchema.parse(response.data);
3. 非空断言
// BAD
const element = document.getElementById('app')!;
// GOOD
const element = document.getElementById('app');
if (!element) {
throw new Error('App element not found');
}
// GOOD - Optional chaining when appropriate
const value = element?.textContent ?? 'default';
4. 复杂条件判断
// BAD
if (user && user.isActive && user.role === 'admin' && !user.suspended) {
// ...
}
// GOOD - Extract to function
function canAccessAdmin(user: User | null): user is User {
return (
user !== null &&
user.isActive &&
user.role === 'admin' &&
!user.suspended
);
}
if (canAccessAdmin(user)) {
// ...
}
5. 函数过长
// BAD - 100+ line function
async function processOrder(order: Order) {
// validation
// calculation
// database operations
// notifications
// logging
}
// GOOD - Split responsibilities
async function processOrder(order: Order) {
validateOrder(order);
const total = calculateTotal(order);
await saveOrder(order, total);
await notifyUser(order);
logOrderProcessed(order);
}
提交前设置
package.json 脚本
{
"scripts": {
"lint": "biome check .",
"lint:fix": "biome check --write .",
"typecheck": "tsc --noEmit",
"quality": "npm run typecheck && npm run lint"
}
}
Husky + lint-staged
npm install -D husky lint-staged
npx husky init
// package.json
{
"lint-staged": {
"*.{ts,tsx,js,jsx}": [
"biome check --write --no-errors-on-unmatched"
]
}
}
# .husky/pre-commit
npx lint-staged
VS Code 设置
// .vscode/settings.json
{
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports.biome": "explicit",
"quickfix.biome": "explicit"
},
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
质量指标目标
| 指标 | 目标 | 工具 |
|---|---|---|
| 圈复杂度 | < 10 | ESLint complexity 规则 |
| 认知复杂度 | < 15 | Biome/SonarQube |
| 函数长度 | < 50 行 | ESLint max-lines-per-function |
| 文件长度 | < 300 行 | ESLint max-lines |
| 嵌套深度 | < 4 层 | ESLint max-depth |
| 参数数量 | < 4 | ESLint max-params |
反模式
| 反模式 | 不良影响 | 正确做法 |
|---|---|---|
到处使用 any | 破坏类型安全 | 使用适当的类型或 unknown |
as 类型断言 | 可能导致运行时错误 | 使用类型守卫或 Zod |
! 非空断言 | 可能在运行时遇到 null | 正确检查 null |
| 在行内禁用 lint 规则 | 造成技术债务 | 修复问题或进行全局配置 |
@ts-ignore | 隐藏真实错误 | 添加注释并使用 @ts-expect-error |
| 未启用严格模式 | 保证较弱 | 启用所有严格标志 |
快速故障排查
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| ESLint 在大型项目中运行缓慢 | 类型感知规则开销较大 | 使用项目引用和缓存 |
| Biome 与 ESLint 冲突 | 两者都在尝试格式化 | 使用 Biome 格式化,使用 ESLint 检查类型规则 |
| lint 未捕获 TypeScript 错误 | 需要类型感知规则 | 将 typescript-eslint 与 projectService 搭配使用 |
| 导入顺序不一致 | 未启用自动整理 | 启用 Biome organizeImports |
| 提交前检查太慢 | 正在检查所有文件 | 使用 lint-staged 仅检查已更改的文件 |
相关技能
评论
支持 Markdown