# Typescript Best Practices

> Use when writing or reviewing TypeScript for type safety, advanced types, API boundaries, strict-mode migrations, and common anti-pattern avoidance.

- Skill: `seaworld008/typescript-best-practices` (Agent Skill)
- Install (CLI): `npx skillmds add seaworld008/typescript-best-practices`
- Raw SKILL.md: https://api.skillmd.com/api/skills/seaworld008/typescript-best-practices/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: seaworld008 (https://skillmd.com/u/seaworld008)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/seaworld008/typescript-best-practices

---


# TypeScript Best Practices

TypeScript is more than just "JavaScript with types." It is a powerful structural type system that can provide profound safety if used correctly. This skill guides you through professional patterns and advanced type programming.

## 触发条件

- 正在启动一个新的中大型 Web 项目（React/Vue/Node.js）。
- 需要重构现有的 JS 代码库，并引入类型安全。
- 正在开发一个面向外部开发者的 npm 包。
- 需要在 monorepo 架构中管理跨项目的共享类型定义。
- 团队代码库中充斥着大量的 `any` 或 `as any`，亟需纠正。

## 核心能力

### 1. 高级类型 (Advanced Types)
- **Conditional Types**: 依据类型 T 的属性返回不同的类型 U 或 V（如 `T extends U ? X : Y`）。
- **Template Literal Types**: 使用模板字符串语法操作字符串字面量类型。
- **Mapped Types**: 基于现有类型生成新类型（如 `Partial`, `Readonly`, `Record`）。
- **Utility Types**: 合理组合内置工具类，实现灵活的数据模型定义。

### 2. 类型守卫 (Type Guards & Assertions)
- **User-Defined Guards**: 使用 `is` 关键字编写自定义判断函数。
- **In/Instanceof/Typeof**: 在运行时进行收缩（Type Narrowing）。
- **Assertion Functions**: 结合测试或异常处理的类型断言。

### 3. 泛型约束 (Generic Constraints)
- **Extends Keyword**: 为泛型注入约束条件，确保类型具备某些属性。
- **Default Generic Types**: 提供合理的缺省值以简化 API。
- **Generic Inference**: 利用 TypeScript 的推断能力，减少显式声明。

### 4. 可辨识联合 (Discriminated Unions)
这是 TS 处理多种状态（如 Loading/Success/Error）的最佳实践。
- **Common Property**: 定义一个共同的、单值（literal）属性（如 `kind`, `type`, `status`）。
- **Exhaustiveness Checking**: 使用 `never` 类型确保 `switch/case` 覆盖了所有可能的分支。

### 5. 运行时校验 (Zod/Valibot)
TypeScript 仅在编译时有效。对于外部数据（API 响应、表单输入），必须在运行时校验。
- **Schema First**: 先定义 Zod Schema，再利用 `z.infer<T>` 生成静态类型。
- **Safe Parsing**: 优雅处理校验失败，并提供语义化的错误信息。
- **Coercion**: 自动进行简单的数据转换（如字符串转数字）。

### 6. tsconfig 最佳配置
- **strict: true**: 这是所有生产项目的起点。
- **exactOptionalPropertyTypes**: 区分 `undefined` 和“未设置”。
- **noUnusedLocals / noUnusedParameters**: 强制代码整洁。
- **skipLibCheck**: 提高编译速度。

### 7. Monorepo 类型共享
- **Project References**: 在大型项目中分块编译，加速构建。
- **Internal vs Public Types**: 明确哪些类型可以作为库导出。

## 常用命令/模板

### Discriminated Unions 示例
```typescript
type ApiResponse = 
  | { status: 'success'; data: string[] }
  | { status: 'error'; message: string }
  | { status: 'loading' };

function handleResponse(response: ApiResponse) {
  switch (response.status) {
    case 'success':
      console.log(response.data.map(d => d.toUpperCase()));
      break;
    case 'error':
      console.error(response.message);
      break;
    case 'loading':
      showSpinner();
      break;
    default:
      // 这里的 response 是 never 类型，确保所有 case 都已处理
      const _exhaustiveCheck: never = response;
      return _exhaustiveCheck;
  }
}
```

### Zod 运行时校验模板
```typescript
import { z } from 'zod';

const UserSchema = z.object({
  id: z.string().uuid(),
  username: z.string().min(3),
  email: z.string().email(),
  role: z.enum(['admin', 'user']),
});

// 从 Schema 提取静态类型
type User = z.infer<typeof UserSchema>;

async function fetchUser(id: string): Promise<User> {
  const response = await fetch(`/api/users/${id}`);
  const data = await response.json();
  
  // 关键：在运行时通过 Zod 校验外部数据
  return UserSchema.parse(data);
}
```

### 推荐的 tsconfig 核心配置
```json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "NodeNext",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "exactOptionalPropertyTypes": true,
    "noUnusedLocals": true
  }
}
```

## 边界与限制

- **过度设计**: 不要为了展示技巧而编写难以理解的高阶类型。
- **any 的诱惑**: 在遇到复杂的第三方库没有提供类型定义时，团队容易退缩回 `any`。
- **编译性能**: 极其复杂的模板字符串类型和深度嵌套的条件类型会显著拖慢编译和 IDE 响应。
- **无法完全保证**: 仍然需要后端和 API 文档的协作，仅前端的 TS 无法防止后端返回了错误格式的数据（除非使用 Zod 校验）。
- **运行时开销**: 只有像 Zod 这样的库有运行时开销，普通的 TS 类型声明在 JS 中是零开销的。

---
*Generated by Skill Master - Professional Edition*

