typescript-workflow

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

TypeScript/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

工具矩阵

TaskToolCommand
Lint + FormatBiome
bun run biome check --apply .
Type checktsc
bun run tsc --noEmit
Dead codets-prune
bun run ts-prune
TestBun test
bun test
Coveragec8
bun run c8 bun test
任务工具命令
代码检查+格式化Biome
bun run biome check --apply .
类型检查tsc
bun run tsc --noEmit
死代码检测ts-prune
bun run ts-prune
测试Bun test
bun test
测试覆盖率c8
bun run c8 bun test

CRITICAL: Bun Package Manager

重要提示:Bun包管理器

You MUST use Bun commands for all package and runtime operations in Bun projects:
bash
undefined
在Bun项目中,所有包管理和运行时操作必须使用Bun命令
bash
undefined

Package 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 packages
bun list # 列出已安装的包 bun outdated # 检查依赖更新

**Bun的优势:**
- 原生支持TypeScript(无需转译配置)
- 速度显著快于Node.js
- 一体化工具(包管理器、运行时、测试运行器)
- 更小的node_modules体积
- 对大多数包可直接兼容Node.js

Module 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
package.json
, specify module type:
json
{
  "type": "module",
  "name": "my-app",
  "version": "1.0.0"
}
package.json
中指定模块类型:
json
{
  "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/biome
Configuration (
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"
    }
  }
}
Usage:
bash
undefined
Biome是推荐的一体化代码检查与格式化工具,它替代了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
undefined

Check 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 .
undefined
bun run biome check .
undefined

Legacy: ESLint + Prettier

遗留方案:ESLint + Prettier

If a project uses ESLint/Prettier, migration to Biome is RECOMMENDED. For legacy support:
bash
undefined
如果项目仍在使用ESLint/Prettier,建议迁移到Biome。如需遗留支持:
bash
undefined

ESLint

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/
undefined
bun add --dev prettier bun run prettier --write src/
undefined

Naming Conventions

命名规范

File Naming

文件命名

  • Components: PascalCase -
    UserProfile.tsx
    ,
    LoginForm.tsx
  • Utilities/Helpers: camelCase -
    formatDate.ts
    ,
    apiClient.ts
  • Types/Interfaces: PascalCase -
    User.ts
    ,
    ApiResponse.ts
  • Constants: UPPER_SNAKE_CASE -
    API_ENDPOINTS.ts
    ,
    CONFIG.ts
  • Test files:
    .test.ts
    or
    .spec.ts
    suffix -
    user.service.test.ts
  • 组件文件:PascalCase -
    UserProfile.tsx
    ,
    LoginForm.tsx
  • 工具/辅助文件:camelCase -
    formatDate.ts
    ,
    apiClient.ts
  • 类型/接口文件:PascalCase -
    User.ts
    ,
    ApiResponse.ts
  • 常量文件:UPPER_SNAKE_CASE -
    API_ENDPOINTS.ts
    ,
    CONFIG.ts
  • 测试文件:以
    .test.ts
    .spec.ts
    结尾 -
    user.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
    any
    - use
    unknown
    and type narrowing if needed
  • Avoid implicit
    any
    - enable
    noImplicitAny
    in tsconfig.json
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
    并配合类型收窄
  • 避免隐式
    any
    :在tsconfig.json中启用
    noImplicitAny
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.lock
project/
├── src/
│   ├── main.ts              # 入口文件
│   ├── types/               # 类型定义
│   ├── services/            # 业务逻辑
│   ├── repositories/        # 数据访问层
│   ├── models/              # 数据模型
│   ├── handlers/            # 请求/事件处理器
│   ├── middleware/          # Express/Web中间件
│   ├── utils/               # 工具函数
│   └── config/              # 配置文件
├── tests/                   # 单元测试与集成测试
├── dist/                    # 编译输出(忽略Git提交)
├── package.json
├── tsconfig.json
├── biome.json
└── bun.lock

Import 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
    any
    - use
    unknown
    and type guards
  • 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
.claude/CLAUDE.md
in the project directory.
  • Next.js相关内容 → 查看
    nextjs-workflow
  • React相关内容 → 查看
    react-workflow
  • 数据库迁移 → 查看
    database-workflow

注意: 针对项目特定的TypeScript模式,请查看项目目录中的.claude/CLAUDE.md文件。