代码规范
本文档定义了XAI-SDK项目的代码规范和最佳实践,确保代码的一致性、可读性和可维护性。
📋 总体原则
核心理念
- 一致性:保持代码风格的一致性
- 可读性:代码应该易于理解和维护
- 简洁性:避免不必要的复杂性
- 安全性:遵循安全编码实践
- 性能:考虑性能影响
代码质量标准
- 测试覆盖率: >= 90%
- 复杂度: 圈复杂度 <= 10
- 文件大小: <= 500行
- 函数长度: <= 50行
- 参数数量: <= 5个
🎯 TypeScript规范
基本配置
json
// tsconfig.json
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"exactOptionalPropertyTypes": true
}
}
类型定义
接口命名
typescript
// ✅ 好的做法
interface UserConfig {
name: string;
age: number;
}
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
// ❌ 避免的做法
interface IUserConfig {
// 不要使用I前缀
name: string;
age: number;
}
类型别名
typescript
// ✅ 好的做法
type EventType = 'click' | 'hover' | 'focus';
type UserId = string;
type Callback<T> = (data: T) => void;
// ❌ 避免的做法
type eventType = 'click' | 'hover' | 'focus'; // 首字母应大写
泛型约束
typescript
// ✅ 好的做法
interface Identifiable {
id: string;
}
function updateEntity<T extends Identifiable>(entity: T): T {
// 实现
return entity;
}
// ❌ 避免的做法
function updateEntity<T>(entity: T): T {
// 缺少约束,类型不安全
return entity;
}
函数定义
函数签名
typescript
// ✅ 好的做法
function processUser(
user: User,
options: ProcessOptions = {}
): Promise<ProcessResult> {
// 实现
}
// 箭头函数用于简单操作
const formatName = (firstName: string, lastName: string): string =>
`${firstName} ${lastName}`;
// ❌ 避免的做法
function processUser(user: any, options?: any): any {
// 类型不明确
}
异步函数
typescript
// ✅ 好的做法
async function fetchUserData(userId: string): Promise<User> {
try {
const response = await api.get(`/users/${userId}`);
return response.data;
} catch (error) {
throw new UserNotFoundError(`User ${userId} not found`);
}
}
// ❌ 避免的做法
function fetchUserData(userId: string): Promise<any> {
return api
.get(`/users/${userId}`)
.then(response => response.data)
.catch(error => {
// 错误处理不当
console.log(error);
});
}
类定义
类结构
typescript
// ✅ 好的做法
class UserManager {
private readonly users: Map<string, User> = new Map();
private readonly logger: Logger;
constructor(logger: Logger) {
this.logger = logger;
}
public async createUser(userData: CreateUserData): Promise<User> {
this.validateUserData(userData);
const user = new User(userData);
this.users.set(user.id, user);
this.logger.info(`User created: ${user.id}`);
return user;
}
private validateUserData(userData: CreateUserData): void {
if (!userData.email) {
throw new ValidationError('Email is required');
}
}
}
访问修饰符
typescript
// ✅ 明确使用访问修饰符
class ApiClient {
private readonly baseUrl: string;
protected readonly timeout: number;
public readonly version: string;
public constructor(config: ApiConfig) {
this.baseUrl = config.baseUrl;
this.timeout = config.timeout ?? 5000;
this.version = config.version;
}
}
🎨 命名规范
变量和函数
typescript
// ✅ 好的做法
const userName = 'john_doe';
const isUserActive = true;
const userCount = 42;
function getUserById(id: string): User | null {
// 实现
}
function calculateTotalPrice(items: Item[]): number {
// 实现
}
// ❌ 避免的做法
const u = 'john_doe'; // 名称太短
const user_name = 'john_doe'; // 使用下划线
const UserName = 'john_doe'; // 首字母大写(应该是常量)
function calc(items: any[]): number {
// 名称不明确
}
常量
typescript
// ✅ 好的做法
const MAX_RETRY_COUNT = 3;
const API_ENDPOINTS = {
USERS: '/api/users',
POSTS: '/api/posts',
} as const;
const DEFAULT_CONFIG: Readonly<Config> = {
timeout: 5000,
retries: 3,
};
// ❌ 避免的做法
const maxRetryCount = 3; // 应该全大写
const apiEndpoints = {
users: '/api/users', // 应该全大写
};
类和接口
typescript
// ✅ 好的做法
class HttpClient {
// 实现
}
interface DatabaseConnection {
connect(): Promise<void>;
disconnect(): Promise<void>;
}
type RequestHandler = (req: Request) => Promise<Response>;
// ❌ 避免的做法
class httpClient {
// 首字母应大写
// 实现
}
interface databaseConnection {
// 首字母应大写
// 实现
}
文件命名
// ✅ 好的做法
user-manager.ts
api-client.ts
config.types.ts
user.test.ts
utils.spec.ts
// ❌ 避免的做法
UserManager.ts
APIClient.ts
user_manager.ts
📁 文件组织
目录结构
src/
├── core/ # 核心功能
│ ├── sdk.ts
│ ├── config.ts
│ └── types.ts
├── adapters/ # 适配器
│ ├── base/
│ │ ├── adapter.ts
│ │ ├── types.ts
│ │ └── index.ts
│ ├── openai/
│ └── anthropic/
├── plugins/ # 插件
├── tools/ # 工具
├── utils/ # 工具函数
│ ├── validation.ts
│ ├── formatting.ts
│ └── index.ts
└── types/ # 全局类型
├── common.ts
├── api.ts
└── index.ts
导入导出
导入顺序
typescript
// ✅ 好的做法
// 1. Node.js内置模块
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
// 2. 第三方库
import axios from 'axios';
import { z } from 'zod';
// 3. 内部模块(按路径深度排序)
import { Config } from '../config';
import { Logger } from '../utils/logger';
import { User } from './user';
// 4. 类型导入(分组)
import type { ApiResponse } from '../types/api';
import type { UserData } from './types';
导出方式
typescript
// ✅ 好的做法 - 命名导出
export class UserManager {
// 实现
}
export interface UserConfig {
// 定义
}
export type UserId = string;
// 默认导出用于主要功能
export default class XAI_SDK {
// 实现
}
// ❌ 避免的做法
export default {
UserManager,
UserConfig,
}; // 避免对象形式的默认导出
索引文件
typescript
// src/adapters/index.ts
export { BaseAdapter } from './base';
export { OpenAIAdapter } from './openai';
export { AnthropicAdapter } from './anthropic';
export type { AdapterConfig } from './base/types';
export type { OpenAIConfig } from './openai/types';
export type { AnthropicConfig } from './anthropic/types';
🔧 ESLint配置
基础配置
javascript
// eslint.config.js
import js from '@eslint/js';
import typescript from '@typescript-eslint/eslint-plugin';
import typescriptParser from '@typescript-eslint/parser';
export default [
js.configs.recommended,
{
files: ['**/*.ts', '**/*.tsx'],
languageOptions: {
parser: typescriptParser,
parserOptions: {
ecmaVersion: 2022,
sourceType: 'module',
project: './tsconfig.json',
},
},
plugins: {
'@typescript-eslint': typescript,
},
rules: {
// TypeScript规则
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/prefer-const': 'error',
'@typescript-eslint/no-non-null-assertion': 'error',
// 代码风格
'prefer-const': 'error',
'no-var': 'error',
'object-shorthand': 'error',
'prefer-template': 'error',
// 最佳实践
eqeqeq: ['error', 'always'],
'no-console': 'warn',
'no-debugger': 'error',
},
},
];
自定义规则
javascript
// 项目特定规则
rules: {
// 强制使用特定的错误类型
'prefer-custom-error': 'error',
// 禁止使用console.log(除了特定情况)
'no-console': ['error', { allow: ['warn', 'error'] }],
// 强制异步函数返回Promise
'@typescript-eslint/promise-function-async': 'error',
// 禁止空的catch块
'no-empty': ['error', { allowEmptyCatch: false }]
}
🎨 Prettier配置
javascript
// prettier.config.js
export default {
// 基础格式
printWidth: 80,
tabWidth: 2,
useTabs: false,
semi: false,
singleQuote: true,
quoteProps: 'as-needed',
// 尾随逗号
trailingComma: 'es5',
// 括号
bracketSpacing: true,
bracketSameLine: false,
arrowParens: 'avoid',
// 换行
endOfLine: 'lf',
// TypeScript
parser: 'typescript',
// 覆盖特定文件类型
overrides: [
{
files: '*.json',
options: {
parser: 'json',
printWidth: 120,
},
},
{
files: '*.md',
options: {
parser: 'markdown',
printWidth: 100,
proseWrap: 'always',
},
},
],
};
📝 注释规范
JSDoc注释
typescript
/**
* 用户管理器,负责用户的创建、更新和删除操作
*
* @example
* ```typescript
* const manager = new UserManager(logger)
* const user = await manager.createUser({
* name: 'John Doe',
* email: 'john@example.com'
* })
* ```
*/
class UserManager {
/**
* 创建新用户
*
* @param userData - 用户数据
* @param options - 创建选项
* @returns 创建的用户对象
*
* @throws {ValidationError} 当用户数据无效时
* @throws {DuplicateUserError} 当用户已存在时
*
* @example
* ```typescript
* const user = await manager.createUser({
* name: 'John Doe',
* email: 'john@example.com'
* })
* ```
*/
async createUser(
userData: CreateUserData,
options: CreateUserOptions = {}
): Promise<User> {
// 实现
}
}
内联注释
typescript
// ✅ 好的做法
function calculatePrice(items: Item[]): number {
// 计算基础价格
const basePrice = items.reduce((sum, item) => sum + item.price, 0);
// 应用折扣(如果有)
const discount = calculateDiscount(basePrice);
// 添加税费
const tax = basePrice * TAX_RATE;
return basePrice - discount + tax;
}
// ❌ 避免的做法
function calculatePrice(items: Item[]): number {
const basePrice = items.reduce((sum, item) => sum + item.price, 0); // 计算价格
const discount = calculateDiscount(basePrice); // 折扣
const tax = basePrice * TAX_RATE; // 税
return basePrice - discount + tax; // 返回总价
}
TODO注释
typescript
// ✅ 好的做法
// TODO(username): 添加缓存机制以提高性能 - Issue #123
// FIXME(username): 修复并发访问时的竞态条件 - 2024-01-15
// HACK(username): 临时解决方案,等待上游库修复
// ❌ 避免的做法
// TODO: 优化这个函数
// FIXME: 有bug
🧪 测试规范
测试文件结构
typescript
// user-manager.test.ts
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { UserManager } from '../user-manager';
import { createMockLogger } from '../../test-utils';
describe('UserManager', () => {
let userManager: UserManager;
let mockLogger: MockLogger;
beforeEach(() => {
mockLogger = createMockLogger();
userManager = new UserManager(mockLogger);
});
afterEach(() => {
// 清理资源
});
describe('createUser', () => {
it('should create user with valid data', async () => {
// Arrange
const userData = {
name: 'John Doe',
email: 'john@example.com',
};
// Act
const user = await userManager.createUser(userData);
// Assert
expect(user).toBeDefined();
expect(user.name).toBe(userData.name);
expect(user.email).toBe(userData.email);
});
it('should throw ValidationError for invalid email', async () => {
// Arrange
const userData = {
name: 'John Doe',
email: 'invalid-email',
};
// Act & Assert
await expect(userManager.createUser(userData)).rejects.toThrow(
ValidationError
);
});
});
});
测试命名
typescript
// ✅ 好的做法
describe('UserManager', () => {
describe('createUser', () => {
it('should create user with valid data', () => {});
it('should throw ValidationError when email is invalid', () => {});
it('should throw DuplicateUserError when user already exists', () => {});
});
describe('updateUser', () => {
it('should update existing user', () => {});
it('should throw UserNotFoundError when user does not exist', () => {});
});
});
// ❌ 避免的做法
describe('UserManager', () => {
it('test1', () => {}); // 名称不明确
it('should work', () => {}); // 太模糊
it('createUser should create user and updateUser should update user', () => {}); // 测试多个功能
});
🚨 错误处理
自定义错误类
typescript
// ✅ 好的做法
export class ValidationError extends Error {
constructor(
message: string,
public readonly field?: string,
public readonly code: string = 'VALIDATION_ERROR'
) {
super(message);
this.name = 'ValidationError';
}
}
export class UserNotFoundError extends Error {
constructor(
public readonly userId: string,
public readonly code: string = 'USER_NOT_FOUND'
) {
super(`User with ID ${userId} not found`);
this.name = 'UserNotFoundError';
}
}
错误处理模式
typescript
// ✅ 好的做法
async function processUser(userId: string): Promise<ProcessResult> {
try {
const user = await userRepository.findById(userId);
if (!user) {
throw new UserNotFoundError(userId);
}
const result = await processUserData(user);
return result;
} catch (error) {
if (error instanceof UserNotFoundError) {
logger.warn(`User not found: ${userId}`);
throw error;
}
if (error instanceof ValidationError) {
logger.warn(`Validation failed: ${error.message}`);
throw error;
}
logger.error('Unexpected error processing user', { userId, error });
throw new ProcessingError('Failed to process user', { cause: error });
}
}
// ❌ 避免的做法
async function processUser(userId: string): Promise<any> {
try {
const user = await userRepository.findById(userId);
return await processUserData(user);
} catch (error) {
console.log(error); // 不当的错误处理
return null;
}
}
📊 性能最佳实践
异步操作
typescript
// ✅ 好的做法
async function processUsers(userIds: string[]): Promise<User[]> {
// 并行处理
const users = await Promise.all(
userIds.map(id => userRepository.findById(id))
);
return users.filter(user => user !== null);
}
// 批量操作
async function createUsers(usersData: CreateUserData[]): Promise<User[]> {
return await userRepository.createMany(usersData);
}
// ❌ 避免的做法
async function processUsers(userIds: string[]): Promise<User[]> {
const users: User[] = [];
// 串行处理,性能差
for (const id of userIds) {
const user = await userRepository.findById(id);
if (user) {
users.push(user);
}
}
return users;
}
内存管理
typescript
// ✅ 好的做法
class DataProcessor {
private readonly cache = new Map<string, ProcessedData>();
private readonly maxCacheSize = 1000;
process(data: RawData): ProcessedData {
const key = this.generateCacheKey(data);
if (this.cache.has(key)) {
return this.cache.get(key)!;
}
const processed = this.processData(data);
// 限制缓存大小
if (this.cache.size >= this.maxCacheSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, processed);
return processed;
}
dispose(): void {
this.cache.clear();
}
}
🔒 安全最佳实践
输入验证
typescript
// ✅ 好的做法
import { z } from 'zod';
const CreateUserSchema = z.object({
name: z.string().min(1).max(100),
email: z.string().email(),
age: z.number().int().min(0).max(150).optional(),
});
function createUser(userData: unknown): Promise<User> {
const validatedData = CreateUserSchema.parse(userData);
return userRepository.create(validatedData);
}
// ❌ 避免的做法
function createUser(userData: any): Promise<User> {
// 没有验证,不安全
return userRepository.create(userData);
}
敏感信息处理
typescript
// ✅ 好的做法
class ApiClient {
private readonly apiKey: string;
constructor(apiKey: string) {
this.apiKey = apiKey;
}
private getHeaders(): Record<string, string> {
return {
Authorization: `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
};
}
// 日志中不暴露敏感信息
private logRequest(url: string, method: string): void {
logger.info('API request', {
url,
method,
// 不记录Authorization header
});
}
}
遵循这些代码规范将帮助我们维护高质量、一致的代码库。如有疑问或建议,请在团队讨论中提出。