typescript-refactoring-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

TypeScript Refactoring Patterns

TypeScript重构模式

Core Principles

核心原则

  1. Type Narrowing Over Type Assertions - Use type guards and discriminated unions instead of
    as
    casts
  2. Const Assertions for Literals - Use
    as const
    for immutable literal types
  3. Generic Constraints - Prefer
    extends
    constraints over
    any
  4. Branded Types - Use branded types for domain-specific validation
  1. 类型收窄优先于类型断言 - 使用类型守卫和可辨识联合替代
    as
    强制转换
  2. 字面量使用const断言 - 对不可变字面量类型使用
    as const
  3. 泛型约束 - 优先使用
    extends
    约束而非
    any
  4. 品牌类型(Branded Types) - 使用品牌类型实现领域特定的验证

Refactoring Patterns

重构模式

Extract Discriminated Union

提取可辨识联合

When you see multiple boolean flags, refactor to discriminated union:
typescript
// Before
interface User {
  isAdmin: boolean;
  isGuest: boolean;
  permissions?: string[];
}

// After
type User =
  | { role: 'admin'; permissions: string[] }
  | { role: 'guest' }
  | { role: 'member'; permissions: string[] };
当你看到多个布尔标志时,重构为可辨识联合:
typescript
// Before
interface User {
  isAdmin: boolean;
  isGuest: boolean;
  permissions?: string[];
}

// After
type User =
  | { role: 'admin'; permissions: string[] }
  | { role: 'guest' }
  | { role: 'member'; permissions: string[] };

Replace Conditional with Polymorphism

用多态替代条件判断

When you see switch statements on type, use the strategy pattern:
typescript
// Before
function process(item: Item) {
  switch (item.type) {
    case 'a': return processA(item);
    case 'b': return processB(item);
  }
}

// After
const processors: Record<ItemType, (item: Item) => Result> = {
  a: processA,
  b: processB,
};
const process = (item: Item) => processors[item.type](item);
当你看到基于类型的switch语句时,使用策略模式:
typescript
// Before
function process(item: Item) {
  switch (item.type) {
    case 'a': return processA(item);
    case 'b': return processB(item);
  }
}

// After
const processors: Record<ItemType, (item: Item) => Result> = {
  a: processA,
  b: processB,
};
const process = (item: Item) => processors[item.type](item);

Extract Type Guard

提取类型守卫

When narrowing types, create reusable type guards:
typescript
function isNonNullable<T>(value: T): value is NonNullable<T> {
  return value !== null && value !== undefined;
}

// Usage
const items = array.filter(isNonNullable);
在收窄类型时,创建可复用的类型守卫:
typescript
function isNonNullable<T>(value: T): value is NonNullable<T> {
  return value !== null && value !== undefined;
}

// Usage
const items = array.filter(isNonNullable);

Use Branded Types for Validation

使用品牌类型做验证

Prevent primitive obsession with branded types:
typescript
type UserId = string & { readonly brand: unique symbol };
type Email = string & { readonly brand: unique symbol };

function createUserId(id: string): UserId {
  if (!isValidUuid(id)) throw new Error('Invalid user ID');
  return id as UserId;
}
用品牌类型避免原始类型痴迷:
typescript
type UserId = string & { readonly brand: unique symbol };
type Email = string & { readonly brand: unique symbol };

function createUserId(id: string): UserId {
  if (!isValidUuid(id)) throw new Error('Invalid user ID');
  return id as UserId;
}

Code Smell Detectors

代码异味检测点

Watch for these patterns and refactor:
  • any
    types (replace with
    unknown
    + type guards)
  • Non-null assertions
    !
    (add proper checks)
  • Type assertions
    as
    (use type guards)
  • Optional chaining abuse
    ?.?.?.
    (restructure data)
  • Index signatures without validation
留意以下模式并进行重构:
  • any
    类型(替换为
    unknown
    +类型守卫)
  • 非空断言
    !
    (添加适当的检查)
  • 类型断言
    as
    (使用类型守卫)
  • 滥用可选链
    ?.?.?.
    (重构数据结构)
  • 无验证的索引签名

Quick Wins

快速优化技巧

  1. Enable
    strict: true
    in tsconfig
  2. Use
    satisfies
    for type checking without widening
  3. Prefer
    readonly
    arrays and objects
  4. Use
    unknown
    for external data, validate at boundaries
  1. 在tsconfig中启用
    strict: true
  2. 使用
    satisfies
    进行类型检查而不拓宽类型
  3. 优先使用
    readonly
    数组和对象
  4. 外部数据使用
    unknown
    ,在边界处进行验证