typescript-refactoring-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTypeScript Refactoring Patterns
TypeScript重构模式
Core Principles
核心原则
- Type Narrowing Over Type Assertions - Use type guards and discriminated unions instead of casts
as - Const Assertions for Literals - Use for immutable literal types
as const - Generic Constraints - Prefer constraints over
extendsany - Branded Types - Use branded types for domain-specific validation
- 类型收窄优先于类型断言 - 使用类型守卫和可辨识联合替代强制转换
as - 字面量使用const断言 - 对不可变字面量类型使用
as const - 泛型约束 - 优先使用约束而非
extendsany - 品牌类型(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:
- types (replace with
any+ type guards)unknown - Non-null assertions (add proper checks)
! - Type assertions (use type guards)
as - Optional chaining abuse (restructure data)
?.?.?. - Index signatures without validation
留意以下模式并进行重构:
- 类型(替换为
any+类型守卫)unknown - 非空断言(添加适当的检查)
! - 类型断言(使用类型守卫)
as - 滥用可选链(重构数据结构)
?.?.?. - 无验证的索引签名
Quick Wins
快速优化技巧
- Enable in tsconfig
strict: true - Use for type checking without widening
satisfies - Prefer arrays and objects
readonly - Use for external data, validate at boundaries
unknown
- 在tsconfig中启用
strict: true - 使用进行类型检查而不拓宽类型
satisfies - 优先使用数组和对象
readonly - 外部数据使用,在边界处进行验证
unknown