# TypeScript 编译规约（TypeScript Compilation Standards）

> **模块**: 01_Architecture - TypeScript 编译零错误规约体系  
> **更新日期**: 2026-03-20  
> **适用范围**: 全项目（dashboard、server、node-agent）

---

## 1. 核心原则（Core Principles）

### 1.1 强制认知统一

| 原则 | 说明 | 违反后果 |
|------|------|----------|
| **不允许 any** | 禁止使用 `any` 类型，使用 `unknown` 替代 | 类型安全完全丧失 |
| **不允许隐式类型推断** | 在边界层（API、DTO）必须显式声明类型 | 类型推断污染调用链 |
| **所有数据都有来源定义** | 数据必须通过 Schema / DTO / 类型定义 | 运行时类型错误 |
| **编译错误 = 构建失败** | TypeScript 编译错误必须阻断 CI/CD | 低质量代码进入生产 |
| **类型错误优先级 > 运行时错误** | 优先解决类型问题，而非运行时问题 | 难以调试和维护 |

### 1.2 类型边界分层

必须把类型分成 3 层：

```
接口层（API） → DTO层 → 业务层（Domain）
```

#### 示例

```typescript
// ❌ 错误写法（直接用接口数据）
const price = res.price * 100

// ✅ 正确：必须经过 DTO 转换
type ProductDTO = {
  price: number
}

function transformProduct(data: unknown): ProductDTO {
  if (typeof data !== 'object' || data === null) {
    throw new Error('Invalid product data')
  }
  
  const productData = data as Record<string, unknown>
  
  return {
    price: Number(productData.price) || 0
  }
}
```

#### 规则

- **接口返回 = 不可信**
- **必须经过 transform 才能进入业务层**
- **禁止在业务层直接使用 API 返回的数据**

---

## 2. tsconfig 强约束配置（第一道防线）

### 2.1 生产级严格配置

所有模块的 `tsconfig.json` 必须包含以下配置：

```json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "moduleResolution": "bundler",
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "outDir": "./dist"
  }
}
```

### 2.2 关键约束解释

| 配置项 | 作用 | 防止的问题 |
|--------|------|------------|
| `noUncheckedIndexedAccess` | 防止 `obj[key]` 直接 undefined 崩溃 | 运行时 undefined 错误 |
| `exactOptionalPropertyTypes` | `?` 不再等于 `undefined \| T` | 脏数据污染 |
| `isolatedModules` | 防止某些文件在构建工具中行为不一致 | 构建不一致 |
| `strictNullChecks` | 严格检查 null 和 undefined | 空指针异常 |
| `noImplicitReturns` | 禁止函数隐式返回 | 返回值类型错误 |

### 2.3 各模块配置差异

#### Dashboard（前端）

```json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "jsx": "react-jsx",
    "module": "esnext",
    "moduleResolution": "node"
  }
}
```

#### Server（后端）

```json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "useDefineForClassFields": false
  }
}
```

#### Extension（浏览器插件）

```json
{
  "compilerOptions": {
    "target": "ESNext",
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "jsx": "react-jsx",
    "module": "ESNext",
    "moduleResolution": "Node"
  }
}
```

#### Node-Agent（Node.js 代理）

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "commonjs",
    "lib": ["ES2022"],
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  }
}
```

---

## 3. 代码规约（真正减少 80% 错误）

### 3.1 禁止裸对象（必须类型化）

```typescript
// ❌ 错误
const user = { name: 'xx', age: 18 }

// ✅ 正确
type User = {
  name: string
  age: number
}
const user: User = { name: 'xx', age: 18 }
```

### 3.2 函数必须声明返回类型

```typescript
// ❌ 错误
function getPrice() {
  return 100
}

// ✅ 正确
function getPrice(): number {
  return 100
}
```

**原因**：防止隐式推断污染调用链

### 3.3 所有 API 层必须定义类型

```typescript
// ❌ 错误
axios.get('/api')

// ✅ 正确
interface ApiResponse<T> {
  code: string
  message: string
  data: T
}

interface Product {
  id: string
  name: string
  price: number
}

axios.get<ApiResponse<Product>>('/api')
```

### 3.4 禁止 any（用 unknown 替代）

```typescript
// ❌ 错误
function handle(data: any) {
  return data.price
}

// ✅ 正确
function handle(data: unknown) {
  if (typeof data === 'object' && data !== null && 'price' in data) {
    return (data as { price: unknown }).price
  }
  throw new Error('Invalid data')
}
```

**类型收窄**：使用 `typeof`、`instanceof`、`in` 操作符进行类型收窄

### 3.5 枚举/常量统一化（避免字符串错误）

```typescript
// ❌ 错误
if (status === 'success') {
  // ...
}

// ✅ 正确
enum Status {
  Success = 'success',
  Failed = 'failed',
  Pending = 'pending'
}

if (status === Status.Success) {
  // ...
}
```

### 3.6 类型守卫（Type Guards）

```typescript
interface Product {
  id: string
  name: string
  price: number
}

function isProduct(data: unknown): data is Product {
  return (
    typeof data === 'object' &&
    data !== null &&
    'id' in data &&
    'name' in data &&
    'price' in data &&
    typeof (data as Product).id === 'string' &&
    typeof (data as Product).name === 'string' &&
    typeof (data as Product).price === 'number'
  )
}

function handleData(data: unknown) {
  if (isProduct(data)) {
    // TypeScript 知道 data 是 Product 类型
    console.log(data.name)
  }
}
```

---

## 4. ESLint + TypeScript 规则（第二道防线）

### 4.1 必须安装的依赖

```bash
npm install -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
```

### 4.2 .eslintrc.js 核心规则

```javascript
module.exports = {
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:@typescript-eslint/recommended-requiring-type-checking',
    'plugin:prettier/recommended'
  ],
  parserOptions: {
    project: './tsconfig.json',
    tsconfigRootDir: __dirname
  },
  rules: {
    '@typescript-eslint/no-explicit-any': 'error',
    '@typescript-eslint/explicit-function-return-type': 'error',
    '@typescript-eslint/consistent-type-imports': 'error',
    '@typescript-eslint/no-unused-vars': 'error',
    '@typescript-eslint/no-floating-promises': 'error',
    '@typescript-eslint/no-misused-promises': 'error',
    '@typescript-eslint/strict-boolean-expressions': 'error',
    '@typescript-eslint/no-unnecessary-type-assertion': 'error',
    'prettier/prettier': 'error'
  }
}
```

### 4.3 规则说明

| 规则 | 作用 | 优先级 |
|------|------|--------|
| `@typescript-eslint/no-explicit-any` | 禁止使用 `any` | P0 |
| `@typescript-eslint/explicit-function-return-type` | 强制声明函数返回类型 | P0 |
| `@typescript-eslint/consistent-type-imports` | 统一 import 语法 | P1 |
| `@typescript-eslint/no-floating-promises` | 禁止未处理的 Promise | P0 |
| `@typescript-eslint/strict-boolean-expressions` | 严格布尔表达式 | P1 |

**作用**：在**写代码时就报错（不是编译时）**

---

## 5. 提交前拦截（第三道防线）

### 5.1 安装依赖

```bash
npm install -D husky lint-staged
```

### 5.2 package.json 配置

```json
{
  "scripts": {
    "prepare": "husky install",
    "lint": "eslint . --ext .ts,.tsx",
    "typecheck": "tsc --noEmit"
  },
  "lint-staged": {
    "*.{ts,tsx}": [
      "eslint --fix",
      "tsc --noEmit"
    ]
  }
}
```

### 5.3 启用 Husky 钩子

```bash
npx husky install
npx husky add .husky/pre-commit "npx lint-staged"
```

### 5.4 效果

- 提交代码前自动检查
- 有 TS 错误直接不让 commit
- 自动修复可修复的 ESLint 错误

---

## 6. CI/CD 阶段强制校验（最终防线）

### 6.1 TypeScript 编译检查

```bash
tsc --noEmit
```

### 6.2 CI/CD 配置（GitHub Actions 示例）

```yaml
name: TypeScript CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  typecheck:
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        module: [dashboard, server, node-agent]
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '20'
          cache: 'npm'
          cache-dependency-path: ${{ matrix.module }}/package-lock.json
      
      - name: Install dependencies
        working-directory: ./${{ matrix.module }}
        run: npm ci
      
      - name: Run ESLint
        working-directory: ./${{ matrix.module }}
        run: npm run lint
      
      - name: Type check
        working-directory: ./${{ matrix.module }}
        run: npm run typecheck
      
      - name: Build
        working-directory: ./${{ matrix.module }}
        run: npm run build
```

### 6.3 验证标准

- ❌ 有错误 → 构建失败
- ✅ 0 errors → 才能发布

---

## 7. 架构级避免错误

### 7.1 Schema 驱动（强烈建议）

使用 **zod** 或 **class-validator** 进行运行时校验 + 编译时类型统一

#### 使用 zod

```typescript
import { z } from 'zod'

const ProductSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(1),
  price: z.number().positive(),
  stock: z.number().int().nonnegative()
})

type Product = z.infer<typeof ProductSchema>

// 使用
function validateProduct(data: unknown): Product {
  return ProductSchema.parse(data)
}
```

#### 使用 class-validator

```typescript
import { IsString, IsNumber, Min, IsUUID } from 'class-validator'

class ProductDTO {
  @IsUUID()
  id: string

  @IsString()
  name: string

  @IsNumber()
  @Min(0)
  price: number

  @IsNumber()
  @Min(0)
  stock: number
}
```

### 7.2 统一类型中心（Semantic Hub）

所有类型只允许从 `/types` 目录 import，禁止各模块自己定义

#### 目录结构

```
/types
  /api          # API 接口类型
  /dto          # 数据传输对象
  /domain       # 领域模型类型
  /shared       # 共享类型
```

#### 使用示例

```typescript
// ❌ 错误：各模块自己定义类型
// dashboard/src/pages/Product/Product.tsx
interface Product {
  id: string
  name: string
}

// server/src/models/Product.ts
interface Product {
  id: string
  name: string
  price: number
}

// ✅ 正确：统一类型中心
// types/domain/Product.ts
export interface Product {
  id: string
  name: string
  price: number
  stock: number
}

// dashboard/src/pages/Product/Product.tsx
import { Product } from '@/types/domain/Product'

// server/src/models/Product.ts
import { Product } from '@/types/domain/Product'
```

---

## 8. 终极落地流程

### 8.1 开发流程

```
写代码
  ↓
ESLint 实时报错
  ↓
提交前 lint-staged 拦截
  ↓
CI 执行 tsc
  ↓
部署
```

### 8.2 错误处理优先级

| 优先级 | 错误类型 | 处理方式 |
|--------|----------|----------|
| P0 | TypeScript 编译错误 | 立即修复，阻断提交 |
| P1 | ESLint 错误 | 立即修复，阻断提交 |
| P2 | ESLint 警告 | 建议修复，不阻断 |
| P3 | 代码风格问题 | 自动修复或手动调整 |

---

## 9. AI 代码生成规范

### 9.1 AI 生成代码必须遵守

1. **类型完整性**：所有函数、变量、参数必须有明确类型
2. **类型安全**：禁止使用 `any`，使用 `unknown` + 类型守卫
3. **边界检查**：所有外部数据必须经过 Schema 验证
4. **错误处理**：所有可能失败的操作必须有错误处理
5. **注释规范**：复杂逻辑必须有 JSDoc 注释

### 9.2 AI 代码自动校验流程

```
AI 生成代码
  ↓
自动运行 tsc --noEmit
  ↓
自动运行 eslint --fix
  ↓
有错误 → 自动修复或标记为失败
  ↓
无错误 → 标记为通过
```

---

## 10. 常见错误与解决方案

### 10.1 类型不兼容

```typescript
// ❌ 错误
const price: number = '100'

// ✅ 正确
const price: number = Number('100') || 0
```

### 10.2 可能为 null/undefined

```typescript
// ❌ 错误
const product = getProduct()
console.log(product.name)

// ✅ 正确
const product = getProduct()
if (product) {
  console.log(product.name)
}

// 或使用可选链
console.log(product?.name)
```

### 10.3 数组索引访问

```typescript
// ❌ 错误
const firstItem = items[0]
console.log(firstItem.name)

// ✅ 正确
const firstItem = items[0]
if (firstItem) {
  console.log(firstItem.name)
}

// 或使用非空断言（谨慎使用）
const firstItem = items[0]!
console.log(firstItem.name)
```

### 10.4 Promise 未处理

```typescript
// ❌ 错误
fetch('/api/data')

// ✅ 正确
fetch('/api/data')
  .then(res => res.json())
  .catch(err => console.error(err))

// 或使用 async/await
async function fetchData() {
  try {
    const res = await fetch('/api/data')
    return await res.json()
  } catch (err) {
    console.error(err)
    throw err
  }
}
```

---

## 11. 性能优化建议

### 11.1 类型推断优化

```typescript
// ❌ 错误：过度类型注解
const numbers: number[] = [1, 2, 3]

// ✅ 正确：让 TypeScript 推断
const numbers = [1, 2, 3]
```

### 11.2 避免类型断言

```typescript
// ❌ 错误：过度使用类型断言
const product = data as Product

// ✅ 正确：使用类型守卫
if (isProduct(data)) {
  const product = data
}
```

### 11.3 使用泛型

```typescript
// ❌ 错误：重复代码
function getNumberArray(): number[] {
  return [1, 2, 3]
}

function getStringArray(): string[] {
  return ['a', 'b', 'c']
}

// ✅ 正确：使用泛型
function getArray<T>(items: T[]): T[] {
  return items
}
```

---

## 12. 版本管理

| 版本 | 变更内容 | 日期 |
|------|----------|------|
| 1.0.0 | 初始版本 | 2026-03-20 |

---

## 13. 参考资源

- [TypeScript 官方文档](https://www.typescriptlang.org/docs/)
- [TypeScript ESLint 规则](https://typescript-eslint.io/rules/)
- [zod 文档](https://zod.dev/)
- [Husky 文档](https://typicode.github.io/husky/)
- [lint-staged 文档](https://github.com/okonet/lint-staged)
