257 lines
4.4 KiB
Markdown
257 lines
4.4 KiB
Markdown
|
|
# TypeScript规则
|
|||
|
|
|
|||
|
|
> **入口**: [_index.md](_index.md)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. 核心原则
|
|||
|
|
|
|||
|
|
### 1.1 禁止any
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// ❌ 禁止
|
|||
|
|
function process(data: any) { ... }
|
|||
|
|
const result: any = fetchData();
|
|||
|
|
|
|||
|
|
// ✅ 正确
|
|||
|
|
function process(data: unknown) {
|
|||
|
|
if (typeof data === 'string') {
|
|||
|
|
// 类型收窄后使用
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
interface FetchResult {
|
|||
|
|
id: string;
|
|||
|
|
name: string;
|
|||
|
|
}
|
|||
|
|
const result: FetchResult = fetchData();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 1.2 函数必须声明返回类型
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// ❌ 禁止
|
|||
|
|
function getProduct(id: string) {
|
|||
|
|
return db('cf_product').where({ id }).first();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ✅ 正确
|
|||
|
|
interface Product {
|
|||
|
|
id: string;
|
|||
|
|
name: string;
|
|||
|
|
price: number;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async function getProduct(id: string): Promise<Product | null> {
|
|||
|
|
return db('cf_product').where({ id }).first();
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 1.3 API必须定义类型
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// ❌ 禁止
|
|||
|
|
router.post('/api/v1/products', async (ctx) => {
|
|||
|
|
const body = ctx.request.body; // any
|
|||
|
|
// ...
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// ✅ 正确
|
|||
|
|
interface CreateProductRequest {
|
|||
|
|
name: string;
|
|||
|
|
price: number;
|
|||
|
|
platform: string;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
interface CreateProductResponse {
|
|||
|
|
success: boolean;
|
|||
|
|
data: Product;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
router.post('/api/v1/products', async (ctx) => {
|
|||
|
|
const body = ctx.request.body as CreateProductRequest;
|
|||
|
|
// ...
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 类型定义规范
|
|||
|
|
|
|||
|
|
### 2.1 Schema驱动
|
|||
|
|
|
|||
|
|
类型必须从 Schema(zod)推导,禁止手动定义:
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// ❌ 禁止:手动定义类型
|
|||
|
|
interface Product {
|
|||
|
|
id: string;
|
|||
|
|
name: string;
|
|||
|
|
price: number;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ✅ 正确:从Schema推导
|
|||
|
|
import { z } from 'zod';
|
|||
|
|
|
|||
|
|
const ProductSchema = z.object({
|
|||
|
|
id: z.string(),
|
|||
|
|
name: z.string(),
|
|||
|
|
price: z.number(),
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
type Product = z.infer<typeof ProductSchema>;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.2 统一类型中心
|
|||
|
|
|
|||
|
|
所有类型只从 `/types` 目录导入:
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// ❌ 禁止:各模块重复定义
|
|||
|
|
// services/ProductService.ts
|
|||
|
|
interface Product { ... }
|
|||
|
|
|
|||
|
|
// ✅ 正确:从类型中心导入
|
|||
|
|
import { Product, CreateProductRequest } from '@/types';
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.3 类型边界分层
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
API 返回数据 → Schema 验证 → DTO 转换 → Domain 模型
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 1. API返回(不可信)
|
|||
|
|
const apiData = await fetchProduct();
|
|||
|
|
|
|||
|
|
// 2. Schema验证
|
|||
|
|
const validated = ProductSchema.parse(apiData);
|
|||
|
|
|
|||
|
|
// 3. DTO转换
|
|||
|
|
const dto: ProductDTO = {
|
|||
|
|
id: validated.id,
|
|||
|
|
name: validated.name,
|
|||
|
|
price: validated.price,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 4. Domain模型
|
|||
|
|
const domain: Product = Product.fromDTO(dto);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 编译检查
|
|||
|
|
|
|||
|
|
### 3.1 强制规则
|
|||
|
|
|
|||
|
|
| 规则 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| 编译错误 = 构建失败 | TypeScript 编译错误必须阻断 CI/CD |
|
|||
|
|
| 提交前检查 | 必须通过 `tsc --noEmit` 检查 |
|
|||
|
|
| ESLint 强制 | 必须通过 `@typescript-eslint` 规则检查 |
|
|||
|
|
|
|||
|
|
### 3.2 禁止行为
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// ❌ 禁止:忽略错误
|
|||
|
|
// @ts-ignore
|
|||
|
|
const result = someFunction();
|
|||
|
|
|
|||
|
|
// ❌ 禁止:禁用检查
|
|||
|
|
// @ts-nocheck
|
|||
|
|
function process() { ... }
|
|||
|
|
|
|||
|
|
// ❌ 禁止:将类型改为any来"解决"错误
|
|||
|
|
const data: any = fetchData();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 类型转换
|
|||
|
|
|
|||
|
|
### 4.1 类型守卫
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// ✅ 正确:使用类型守卫
|
|||
|
|
function isProduct(data: unknown): data is Product {
|
|||
|
|
return (
|
|||
|
|
typeof data === 'object' &&
|
|||
|
|
data !== null &&
|
|||
|
|
'id' in data &&
|
|||
|
|
'name' in data &&
|
|||
|
|
'price' in data
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function process(data: unknown) {
|
|||
|
|
if (isProduct(data)) {
|
|||
|
|
// data 类型为 Product
|
|||
|
|
console.log(data.name);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 类型断言
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// ❌ 禁止:过度使用断言
|
|||
|
|
const product = data as Product;
|
|||
|
|
|
|||
|
|
// ✅ 正确:先用Schema验证
|
|||
|
|
const product = ProductSchema.parse(data);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 文件规模限制
|
|||
|
|
|
|||
|
|
| 类型 | 限制 |
|
|||
|
|
|------|------|
|
|||
|
|
| 单文件 | ≤ 1500 行 |
|
|||
|
|
| 单函数 | ≤ 120 行 |
|
|||
|
|
| UI组件 | ≤ 300 行 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 命名规范
|
|||
|
|
|
|||
|
|
### 6.1 文件命名
|
|||
|
|
|
|||
|
|
| 类型 | 格式 | 示例 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| 组件 | PascalCase | `ProductList.tsx` |
|
|||
|
|
| 服务 | PascalCase | `ProductService.ts` |
|
|||
|
|
| 工具 | camelCase | `formatPrice.ts` |
|
|||
|
|
| 类型 | camelCase | `productTypes.ts` |
|
|||
|
|
|
|||
|
|
### 6.2 类型命名
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 接口:不加 I 前缀
|
|||
|
|
interface Product { ... }
|
|||
|
|
|
|||
|
|
// 类型别名:描述性名称
|
|||
|
|
type ProductStatus = 'ACTIVE' | 'INACTIVE';
|
|||
|
|
|
|||
|
|
// 泛型:单字母或描述性名称
|
|||
|
|
function getItems<T>(): T[] { ... }
|
|||
|
|
function transform<Input, Output>(data: Input): Output { ... }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. 检查命令
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 类型检查
|
|||
|
|
npx tsc --noEmit
|
|||
|
|
|
|||
|
|
# 检查错误数量
|
|||
|
|
npx tsc --noEmit 2>&1 | Select-String -Pattern "^src/" | Measure-Object
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
*最后更新: 2026-03-22*
|