typescript-workflow
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTypeScript/JavaScript Projects Workflow
TypeScript/JavaScript项目工作流
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
Guidelines for working with TypeScript and JavaScript projects using Bun as the primary package manager with modern tooling and best practices.
本文档中的关键词“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY”和“OPTIONAL”应按照RFC 2119中的定义进行解读。
本指南介绍使用Bun作为主要包管理器,结合现代工具与最佳实践开发TypeScript和JavaScript项目的方法。
Tool Grid
工具矩阵
| Task | Tool | Command |
|---|---|---|
| Lint + Format | Biome | |
| Type check | tsc | |
| Dead code | ts-prune | |
| Test | Bun test | |
| Coverage | c8 | |
| 任务 | 工具 | 命令 |
|---|---|---|
| 代码检查+格式化 | Biome | |
| 类型检查 | tsc | |
| 死代码检测 | ts-prune | |
| 测试 | Bun test | |
| 测试覆盖率 | c8 | |
CRITICAL: Bun Package Manager
重要提示:Bun包管理器
You MUST use Bun commands for all package and runtime operations in Bun projects:
bash
undefined在Bun项目中,所有包管理和运行时操作必须使用Bun命令:
bash
undefinedPackage management
包管理
bun install # Install dependencies from package.json
bun add <package> # Add production dependency
bun add --dev <package> # Add development dependency
bun remove <package> # Remove dependency
bun install # 从package.json安装依赖
bun add <package> # 添加生产依赖
bun add --dev <package> # 添加开发依赖
bun remove <package> # 移除依赖
Running code and scripts
运行代码与脚本
bun run <script> # Run script defined in package.json
bun <file.ts> # Run TypeScript/JavaScript directly
bun run build # Run build script
bun run <script> # 运行package.json中定义的脚本
bun <file.ts> # 直接运行TypeScript/JavaScript文件
bun run build # 运行构建脚本
Testing
测试
bun test # Run tests with Bun's native test runner
bun test # 使用Bun原生测试运行器执行测试
Package info
包信息查看
bun list # List installed packages
bun outdated # Check for updates
**Benefits of Bun:**
- Native TypeScript support (no transpilation setup)
- Significantly faster than Node.js
- All-in-one tool (package manager, runtime, test runner)
- Smaller node_modules footprint
- Drop-in Node.js compatibility for most packagesbun list # 列出已安装的包
bun outdated # 检查依赖更新
**Bun的优势:**
- 原生支持TypeScript(无需转译配置)
- 速度显著快于Node.js
- 一体化工具(包管理器、运行时、测试运行器)
- 更小的node_modules体积
- 对大多数包可直接兼容Node.jsModule Systems
模块系统
ESM (ECMAScript Modules) - Preferred
ESM(ECMAScript模块)- 推荐使用
Default for Bun projects and modern TypeScript:
typescript
// Import named exports
import { UserService } from './services/user-service';
import { type User } from './types';
// Import default exports
import express from 'express';
// Import with alias
import * as helpers from './utils/helpers';
// Export named
export function getUserById(id: string): Promise<User> {
// ...
}
// Export default
export default UserService;
// Re-export
export { type User } from './types';
export { UserService } from './services/user-service';Bun项目和现代TypeScript的默认选择:
typescript
// 导入命名导出
import { UserService } from './services/user-service';
import { type User } from './types';
// 导入默认导出
import express from 'express';
// 批量导入
import * as helpers from './utils/helpers';
// 导出命名成员
export function getUserById(id: string): Promise<User> {
// ...
}
// 导出默认成员
export default UserService;
// 重导出
export { type User } from './types';
export { UserService } from './services/user-service';CommonJS Fallback
CommonJS兼容方案
Use only when necessary for legacy compatibility:
javascript
// Require imports
const { UserService } = require('./services/user-service');
const express = require('express');
// Module exports
module.exports = UserService;
module.exports = { UserService, UserRepository };仅在需要兼容遗留代码时使用:
javascript
// 使用require导入
const { UserService } = require('./services/user-service');
const express = require('express');
// 使用module.exports导出
module.exports = UserService;
module.exports = { UserService, UserRepository };Mixed Module Usage
混合模块使用
In , specify module type:
package.jsonjson
{
"type": "module",
"name": "my-app",
"version": "1.0.0"
}在中指定模块类型:
package.jsonjson
{
"type": "module",
"name": "my-app",
"version": "1.0.0"
}TypeScript Configuration
TypeScript配置
tsconfig.json Best Practices
tsconfig.json最佳实践
json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020"],
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"allowJs": false,
"outDir": "./dist",
"rootDir": "./src",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@services/*": ["src/services/*"],
"@models/*": ["src/models/*"]
},
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"removeComments": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020"],
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"allowJs": false,
"outDir": "./dist",
"rootDir": "./src",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@services/*": ["src/services/*"],
"@models/*": ["src/models/*"]
},
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"removeComments": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}Key Options Explained
关键配置项说明
- target: ES2020 for modern environments, ES2015 for legacy support
- module: ESNext for Bun/bundlers, CommonJS for Node.js compatibility
- moduleResolution: bundler (for Bun/bundlers), node (for Node.js)
- strict: Enable all strict type checking
- skipLibCheck: Skip type checking of declaration files
- baseUrl + paths: Enable path aliases for cleaner imports
- noUnusedLocals/Parameters: Catch dead code
- target:现代环境使用ES2020,遗留环境使用ES2015
- module:Bun/打包工具使用ESNext,Node.js兼容使用CommonJS
- moduleResolution:bundler(适用于Bun/打包工具),node(适用于Node.js)
- strict:启用所有严格类型检查
- skipLibCheck:跳过声明文件的类型检查
- baseUrl + paths:启用路径别名以简化导入
- noUnusedLocals/Parameters:检测死代码
Code Style and Formatting
代码风格与格式化
Biome (Preferred)
Biome(推荐使用)
Biome is the RECOMMENDED all-in-one tool for linting and formatting. It replaces ESLint and Prettier with faster performance and unified configuration.
Installation:
bash
bun add --dev @biomejs/biomeConfiguration ():
biome.jsonjson
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"organizeImports": {
"enabled": true
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"complexity": {
"noUselessSwitchCase": "error"
},
"style": {
"noNonNullAssertion": "warn"
}
}
},
"javascript": {
"formatter": {
"semicolons": "always",
"quoteStyle": "single",
"trailingCommas": "es5"
}
}
}Usage:
bash
undefinedBiome是推荐的一体化代码检查与格式化工具,它替代了ESLint和Prettier,拥有更快的性能和统一的配置。
安装:
bash
bun add --dev @biomejs/biome配置(biome.json):
json
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"organizeImports": {
"enabled": true
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"complexity": {
"noUselessSwitchCase": "error"
},
"style": {
"noNonNullAssertion": "warn"
}
}
},
"javascript": {
"formatter": {
"semicolons": "always",
"quoteStyle": "single",
"trailingCommas": "es5"
}
}
}使用方法:
bash
undefinedCheck and fix all issues
检查并修复所有问题
bun run biome check --apply .
bun run biome check --apply .
Format only
仅格式化代码
bun run biome format --write .
bun run biome format --write .
Lint only
仅执行代码检查
bun run biome lint .
bun run biome lint .
CI mode (check without fixing)
CI模式(仅检查不修复)
bun run biome check .
undefinedbun run biome check .
undefinedLegacy: ESLint + Prettier
遗留方案:ESLint + Prettier
If a project uses ESLint/Prettier, migration to Biome is RECOMMENDED. For legacy support:
bash
undefined如果项目仍在使用ESLint/Prettier,建议迁移到Biome。如需遗留支持:
bash
undefinedESLint
ESLint
bun add --dev eslint
bun run eslint src/ --fix
bun add --dev eslint
bun run eslint src/ --fix
Prettier
Prettier
bun add --dev prettier
bun run prettier --write src/
undefinedbun add --dev prettier
bun run prettier --write src/
undefinedNaming Conventions
命名规范
File Naming
文件命名
- Components: PascalCase - ,
UserProfile.tsxLoginForm.tsx - Utilities/Helpers: camelCase - ,
formatDate.tsapiClient.ts - Types/Interfaces: PascalCase - ,
User.tsApiResponse.ts - Constants: UPPER_SNAKE_CASE - ,
API_ENDPOINTS.tsCONFIG.ts - Test files: or
.test.tssuffix -.spec.tsuser.service.test.ts
- 组件文件:PascalCase - ,
UserProfile.tsxLoginForm.tsx - 工具/辅助文件:camelCase - ,
formatDate.tsapiClient.ts - 类型/接口文件:PascalCase - ,
User.tsApiResponse.ts - 常量文件:UPPER_SNAKE_CASE - ,
API_ENDPOINTS.tsCONFIG.ts - 测试文件:以或
.test.ts结尾 -.spec.tsuser.service.test.ts
Code Naming
代码命名
typescript
// Classes/Types/Interfaces/Enums: PascalCase
class UserService { /* ... */ }
interface UserRepository { /* ... */ }
enum UserRole { Admin = 'ADMIN', User = 'USER' }
// Methods, properties, variables, functions: camelCase
getUserById(id: string): Promise<User>
const userData = {};
// Private members: camelCase with leading underscore
private _cache: Map<string, User> = new Map();
// Constants: UPPER_SNAKE_CASE
const MAX_RETRIES = 3;
const API_BASE_URL = 'https://api.example.com';
// React hooks: camelCase with use prefix
function useUserData(userId: string) { /* ... */ }typescript
// 类/类型/接口/枚举:PascalCase
class UserService { /* ... */ }
interface UserRepository { /* ... */ }
enum UserRole { Admin = 'ADMIN', User = 'USER' }
// 方法、属性、变量、函数:camelCase
getUserById(id: string): Promise<User>
const userData = {};
// 私有成员:camelCase前缀加下划线
private _cache: Map<string, User> = new Map();
// 常量:UPPER_SNAKE_CASE
const MAX_RETRIES = 3;
const API_BASE_URL = 'https://api.example.com';
// React钩子:camelCase前缀加use
function useUserData(userId: string) { /* ... */ }Type Safety and Annotations
类型安全与注解
Type Hints
类型提示
- Explicit types for function parameters and return values
- MUST NOT use - use
anyand type narrowing if neededunknown - Avoid implicit - enable
anyin tsconfig.jsonnoImplicitAny
typescript
// Function parameters and return types
function processUser(user: User): Promise<ProcessedUser> {
// ...
}
// Arrow functions
const formatName = (first: string, last: string): string => {
return `${first} ${last}`;
};
// Complex types
type ApiResponse<T> = {
status: number;
data: T;
error?: string;
};
interface RequestHandler {
handle(request: Request): Promise<Response>;
}- 函数参数和返回值必须使用显式类型
- 禁止使用类型:如需动态类型,使用
any并配合类型收窄unknown - 避免隐式:在tsconfig.json中启用
anynoImplicitAny
typescript
// 函数参数与返回类型
function processUser(user: User): Promise<ProcessedUser> {
// ...
}
// 箭头函数
const formatName = (first: string, last: string): string => {
return `${first} ${last}`;
};
// 复杂类型
type ApiResponse<T> = {
status: number;
data: T;
error?: string;
};
interface RequestHandler {
handle(request: Request): Promise<Response>;
}Generics
泛型
typescript
// Generic functions
function getById<T extends { id: string }>(items: T[], id: string): T | undefined {
return items.find((item) => item.id === id);
}
// Generic classes
class Repository<T> {
async getById(id: string): Promise<T | null> {
// ...
}
}
// Generic types
type Result<T, E = Error> = { success: true; data: T } | { success: false; error: E };typescript
// 泛型函数
function getById<T extends { id: string }>(items: T[], id: string): T | undefined {
return items.find((item) => item.id === id);
}
// 泛型类
class Repository<T> {
async getById(id: string): Promise<T | null> {
// ...
}
}
// 泛型类型
type Result<T, E = Error> = { success: true; data: T } | { success: false; error: E };Data Validation
数据验证
Use Zod for runtime validation with type inference:
typescript
import { z } from 'zod';
// Schema definition
const UserSchema = z.object({
id: z.string().uuid(),
name: z.string().min(1),
email: z.string().email(),
age: z.number().int().positive().optional(),
});
// Type inference from schema
type User = z.infer<typeof UserSchema>;
// Runtime validation
function createUser(data: unknown): User {
return UserSchema.parse(data);
}
// Safe parsing with error handling
const result = UserSchema.safeParse(data);
if (!result.success) {
console.error(result.error.format());
}使用Zod进行运行时验证并支持类型推断:
typescript
import { z } from 'zod';
// 定义Schema
const UserSchema = z.object({
id: z.string().uuid(),
name: z.string().min(1),
email: z.string().email(),
age: z.number().int().positive().optional(),
});
// 从Schema推断类型
type User = z.infer<typeof UserSchema>;
// 运行时验证
function createUser(data: unknown): User {
return UserSchema.parse(data);
}
// 安全解析并处理错误
const result = UserSchema.safeParse(data);
if (!result.success) {
console.error(result.error.format());
}Project Structure
项目结构
Recommended Directory Layout
推荐目录布局
project/
├── src/
│ ├── main.ts # Entry point
│ ├── types/ # Type definitions
│ ├── services/ # Business logic
│ ├── repositories/ # Data access layer
│ ├── models/ # Data models
│ ├── handlers/ # Request/event handlers
│ ├── middleware/ # Express/web middleware
│ ├── utils/ # Utility functions
│ └── config/ # Configuration
├── tests/ # Unit and integration tests
├── dist/ # Compiled output (gitignored)
├── package.json
├── tsconfig.json
├── biome.json
└── bun.lockproject/
├── src/
│ ├── main.ts # 入口文件
│ ├── types/ # 类型定义
│ ├── services/ # 业务逻辑
│ ├── repositories/ # 数据访问层
│ ├── models/ # 数据模型
│ ├── handlers/ # 请求/事件处理器
│ ├── middleware/ # Express/Web中间件
│ ├── utils/ # 工具函数
│ └── config/ # 配置文件
├── tests/ # 单元测试与集成测试
├── dist/ # 编译输出(忽略Git提交)
├── package.json
├── tsconfig.json
├── biome.json
└── bun.lockImport Patterns
导入模式
typescript
// Absolute imports with path aliases
import { UserService } from '@services/user-service';
import type { User } from '@models/user';
// Relative imports within same feature
import { UserRepository } from '../repositories/user-repository';
import { validateUser } from '../utils/validators';
// Re-exports from index files
export { UserService, UserRepository } from './index';typescript
// 使用路径别名的绝对导入
import { UserService } from '@services/user-service';
import type { User } from '@models/user';
// 同功能模块内的相对导入
import { UserRepository } from '../repositories/user-repository';
import { validateUser } from '../utils/validators';
// 通过index文件重导出
export { UserService, UserRepository } from './index';Error Handling
错误处理
Exception Best Practices
异常处理最佳实践
typescript
// Define custom error classes
class AppError extends Error {
constructor(message: string, public code: string, public statusCode = 500) {
super(message);
this.name = 'AppError';
}
}
class ValidationError extends AppError {
constructor(message: string, public field: string) {
super(message, 'VALIDATION_ERROR', 400);
}
}
class NotFoundError extends AppError {
constructor(message: string) {
super(message, 'NOT_FOUND', 404);
}
}
// Result pattern for explicit error handling
type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E };
async function safeFetchUser(id: string): Promise<Result<User, AppError>> {
try {
const user = await getUser(id);
return { ok: true, value: user };
} catch (error) {
return { ok: false, error: error instanceof AppError ? error : new AppError('Unknown', 'UNKNOWN') };
}
}typescript
// 定义自定义错误类
class AppError extends Error {
constructor(message: string, public code: string, public statusCode = 500) {
super(message);
this.name = 'AppError';
}
}
class ValidationError extends AppError {
constructor(message: string, public field: string) {
super(message, 'VALIDATION_ERROR', 400);
}
}
class NotFoundError extends AppError {
constructor(message: string) {
super(message, 'NOT_FOUND', 404);
}
}
// 结果模式:显式错误处理
type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E };
async function safeFetchUser(id: string): Promise<Result<User, AppError>> {
try {
const user = await getUser(id);
return { ok: true, value: user };
} catch (error) {
return { ok: false, error: error instanceof AppError ? error : new AppError('未知错误', 'UNKNOWN') };
}
}Configuration Management
配置管理
Environment Variables
环境变量
Use Zod for environment validation:
typescript
// env.ts
import { z } from 'zod';
const EnvSchema = z.object({
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
PORT: z.coerce.number().default(3000),
DATABASE_URL: z.string().url(),
API_KEY: z.string(),
});
export default EnvSchema.parse(process.env);使用Zod验证环境变量:
typescript
// env.ts
import { z } from 'zod';
const EnvSchema = z.object({
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
PORT: z.coerce.number().default(3000),
DATABASE_URL: z.string().url(),
API_KEY: z.string(),
});
export default EnvSchema.parse(process.env);Common Async Patterns
常见异步模式
typescript
// Async/await with error handling
async function fetchUserData(id: string): Promise<User> {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) throw new Error('Failed to fetch');
return response.json();
} catch (error) {
console.error('Error fetching user:', error);
throw error;
}
}
// Concurrent operations with Promise.all
async function loadDashboardData(): Promise<DashboardData> {
const [users, products, stats] = await Promise.all([
fetchUsers(),
fetchProducts(),
fetchStats(),
]);
return { users, products, stats };
}typescript
// 带错误处理的Async/await
async function fetchUserData(id: string): Promise<User> {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) throw new Error('获取数据失败');
return response.json();
} catch (error) {
console.error('获取用户数据出错:', error);
throw error;
}
}
// 使用Promise.all并发执行
async function loadDashboardData(): Promise<DashboardData> {
const [users, products, stats] = await Promise.all([
fetchUsers(),
fetchProducts(),
fetchStats(),
]);
return { users, products, stats };
}Testing Integration
测试集成
typescript
import { describe, it, expect, beforeEach } from 'bun:test';
import { UserService } from '@services/user-service';
describe('UserService', () => {
let service: UserService;
beforeEach(() => {
service = new UserService();
});
it('should fetch user by id', async () => {
const user = await service.getById('123');
expect(user).toBeDefined();
expect(user?.id).toBe('123');
});
});See typescript-testing skill for comprehensive testing patterns.
typescript
import { describe, it, expect, beforeEach } from 'bun:test';
import { UserService } from '@services/user-service';
describe('UserService', () => {
let service: UserService;
beforeEach(() => {
service = new UserService();
});
it('应该根据ID获取用户', async () => {
const user = await service.getById('123');
expect(user).toBeDefined();
expect(user?.id).toBe('123');
});
});如需全面的测试模式,请参考typescript-testing技能文档。
Quick Reference
快速参考
Key Rules:
- MUST use Bun commands in Bun projects
- MUST NOT use - use
anyand type guardsunknown - Use ESM (import/export) by default
- Enable strict TypeScript ()
"strict": true - Validate all external input with Zod
- Use custom error classes and Result types
核心规则:
- 必须在Bun项目中使用Bun命令
- 禁止使用类型:使用
any并配合类型守卫unknown - 默认使用ESM(import/export)
- 启用严格TypeScript检查()
"strict": true - 使用Zod验证所有外部输入
- 使用自定义错误类和结果类型
Out of Scope
超出范围
- Next.js specifics → see
nextjs-workflow - React specifics → see
react-workflow - Database migrations → see
database-workflow
Note: For project-specific TypeScript patterns, check in the project directory.
.claude/CLAUDE.md- Next.js相关内容 → 查看
nextjs-workflow - React相关内容 → 查看
react-workflow - 数据库迁移 → 查看
database-workflow
注意: 针对项目特定的TypeScript模式,请查看项目目录中的.claude/CLAUDE.md文件。