mcpField
T
typescript-best-practices

typescript-best-practices

github.com/alleneubank开发503.4k 次安装18 周前更新
代码仓库

关于 typescript-best-practices

面向编码 Agent 的 TypeScript 技能,侧重类型优先设计、运行时验证和语言习惯。处理 React 文件时,建议与 `react-best-practices` 配合使用。

主要功能

  1. 01类型优先建模
  2. 02判别联合与品牌类型
  3. 03使用 Zod 进行运行时验证
  4. 04穷尽式 switch 检查
  5. 05可选的 type-fest 工具

适用场景

  1. 01建模以排除无效状态
  2. 02验证并规范化运行时输入
  3. 03保持 Schema 与推断类型一致

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/alleneubank/claude-code --skill typescript-best-practices

安装后在 Claude Code 中输入/typescript-best-practices确认已加载。

详细介绍

TypeScript 最佳实践

遵循 CLAUDE.md 中以类型优先、函数式和错误处理为核心的模式。本技能仅涵盖语言特定的惯用写法。

与 React 最佳实践搭配使用

处理 React 组件(.tsx、.jsx 文件或 @react 导入)时,始终同时加载 react-best-practices。本技能涵盖 TypeScript 基础知识;React 专属模式(副作用、钩子、引用、组件设计)请参阅专门的 React 技能。

让非法状态无法表示

使用类型系统在编译时阻止无效状态。

互斥状态使用判别联合类型:

// Good: only valid combinations possible
type RequestState<T> =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error'; error: Error };

// Bad: allows invalid combinations like { loading: true, error: Error }
type RequestState<T> = {
  loading: boolean;
  data?: T;
  error?: Error;
};

领域原始类型使用品牌类型:

type UserId = string & { readonly __brand: 'UserId' };
type OrderId = string & { readonly __brand: 'OrderId' };

// Compiler prevents passing OrderId where UserId expected
function getUser(id: UserId): Promise<User> { /* ... */ }

字面量联合类型使用 const 断言:

const ROLES = ['admin', 'user', 'guest'] as const;
type Role = typeof ROLES[number]; // 'admin' | 'user' | 'guest'

// Array and type stay in sync automatically
function isValidRole(role: string): role is Role {
  return ROLES.includes(role as Role);
}

使用 never 检查穷尽式 switch:

type Status = "active" | "inactive";

function processStatus(status: Status): string {
  switch (status) {
    case "active":
      return "processing";
    case "inactive":
      return "skipped";
    default: {
      const _exhaustive: never = status;
      throw new Error(`unhandled status: ${_exhaustive}`);
    }
  }
}

使用 Zod 进行运行时验证

  • 将架构定义为唯一事实来源;使用 z.infer<> 推导 TypeScript 类型。避免重复定义类型和架构。
  • 对于预期可能失败的用户输入,使用 safeParse;对于无效数据意味着错误的信任边界,使用 parse。
  • 使用 .extend()、.pick()、.omit()、.merge() 组合架构,遵循 DRY 原则。
  • 添加 .transform(),在解析时规范化数据(修剪字符串、解析日期)。
import { z } from "zod";

const UserSchema = z.object({
  id: z.string().uuid(),
  email: z.string().email(),
  name: z.string().min(1),
  createdAt: z.string().transform((s) => new Date(s)),
});

type User = z.infer<typeof UserSchema>;

// Strict parsing at trust boundaries — throws if API contract violated
export async function fetchUser(id: string): Promise<User> {
  const response = await fetch(`/api/users/${id}`);
  if (!response.ok) {
    throw new Error(`fetch user ${id} failed: ${response.status}`);
  }
  return UserSchema.parse(await response.json());
}

// Caller handles both success and error from user input
const result = UserSchema.safeParse(formData);
if (!result.success) {
  setErrors(result.error.flatten().fieldErrors);
  return;
}

可选:type-fest

对于超出 TypeScript 内置类型工具范围的高级类型工具,可考虑使用 type-fest:

  • Opaque<T, Token> - 比手动使用 & { __brand } 模式更简洁的品牌类型
  • PartialDeep<T> - 为嵌套对象递归设置为可选
  • ReadonlyDeep<T> - 为不可变数据递归设置为只读
  • SetRequired<T, K> / SetOptional<T, K> - 定向修改字段
  • Simplify<T> - 在 IDE 工具提示中展平复杂的交叉类型
import type { Opaque, PartialDeep } from 'type-fest';

type UserId = Opaque<string, 'UserId'>;
type UserPatch = PartialDeep<User>;

评论

支持 Markdown