reviewing-typescript-code

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

TypeScript Code Quality Patterns

TypeScript代码质量模式

Purpose

目的

Guide for writing and reviewing TypeScript code with proper type safety, clean code principles, functional programming patterns, error handling, and project-specific conventions for the Saleor Configurator codebase.
为Saleor Configurator代码库提供遵循正确类型安全、整洁代码原则、函数式编程模式、错误处理及项目特定规范的TypeScript代码编写与评审指南。

When to Use

适用场景

Configurator-Specific Tasks (Primary Triggers):
  • Adding new entity types (category, product, channel, tax, etc.)
  • Creating services (
    *Service
    classes)
  • Adding repository methods (
    *Repository
    classes)
  • Creating comparators for diff engine (
    *Comparator
    classes)
  • Adding formatters for output (
    *Formatter
    classes)
  • Implementing deployment stages
  • Writing GraphQL queries/mutations
  • Creating Zod schemas for validation
  • Adding error classes (
    *Error
    extends
    BaseError
    )
  • Implementing bootstrap methods (idempotent create/update)
  • Adding diff support for entities
General Writing Tasks:
  • Implementing new features or services
  • Adding new functions or methods
  • Creating TypeScript classes or modules
  • Writing transformation logic
  • Refactoring existing code to clean patterns
Review Tasks:
  • Reviewing code before committing
  • Analyzing pull request changes
  • Checking implementation quality
  • Auditing existing code for improvements
配置器特定任务(主要触发场景):
  • 添加新实体类型(类目、商品、渠道、税费等)
  • 创建服务(
    *Service
    类)
  • 添加仓库方法(
    *Repository
    类)
  • 为差异引擎创建比较器(
    *Comparator
    类)
  • 添加输出格式化器(
    *Formatter
    类)
  • 实现部署阶段
  • 编写GraphQL查询/变更
  • 创建用于验证的Zod模式
  • 添加错误类(
    *Error
    继承自
    BaseError
  • 实现引导方法(幂等创建/更新)
  • 为实体添加差异支持
通用编写任务:
  • 实现新功能或服务
  • 添加新函数或方法
  • 创建TypeScript类或模块
  • 编写转换逻辑
  • 将现有代码重构为整洁模式
评审任务:
  • 提交前的代码评审
  • 分析拉取请求变更
  • 检查实现质量
  • 审计现有代码以寻找改进空间

Table of Contents

目录

Quality Checklist

质量检查表

Use this checklist when writing new code to ensure quality from the start, or when reviewing existing code to identify improvements.
编写新代码时使用此检查表从一开始确保质量,或评审现有代码时识别改进点。

1. Type Safety Analysis

1. 类型安全分析

Critical (Must Fix):
  • No
    any
    types in production code (only allowed in test mocks)
  • No unsafe type assertions (
    as unknown as T
    )
  • No non-null assertions (
    !
    ) without strong justification
  • Proper type guards for runtime validation
Best Practices:
  • Branded types used for domain-specific values (EntitySlug, EntityName)
  • Discriminated unions preferred over inheritance
  • Type inference leveraged where clear
  • Generic constraints properly applied
  • readonly
    used for immutable data
  • satisfies
    operator for type validation with literal preservation
typescript
// BAD - Avoid these patterns
const result: any = someOperation();
const value = maybeUndefined!;
const data = response as unknown as MyType;

// GOOD - Use these patterns
type EntitySlug = string & { readonly __brand: unique symbol };
const isSlugBasedEntity = (entity: unknown): entity is { slug: string } => { ... };
const ENTITY_TYPES = ['categories', 'products'] as const;

// GOOD - satisfies for type validation while preserving literal types
interface ConfigShape {
  readonly MAX_ITEMS: number;
  readonly TIMEOUT: number;
}
const CONFIG = {
  MAX_ITEMS: 10,
  TIMEOUT: 5000,
} as const satisfies ConfigShape;
// CONFIG.MAX_ITEMS is `10`, not just `number`

// GOOD - Template literal type validation with satisfies
type CliFlag = `--${string}`;
const FLAGS = ["--json", "--verbose"] as const satisfies readonly CliFlag[];
关键问题(必须修复):
  • 生产代码中无
    any
    类型(仅允许在测试模拟中使用)
  • 无不安全类型断言(
    as unknown as T
  • 无无充分理由的非空断言(
    !
  • 为运行时验证使用正确的类型守卫
最佳实践:
  • 为领域特定值使用品牌类型(EntitySlug、EntityName)
  • 优先使用可区分联合而非继承
  • 在清晰的场景下利用类型推断
  • 正确应用泛型约束
  • 为不可变数据使用
    readonly
  • 使用
    satisfies
    操作符进行类型验证并保留字面量类型
typescript
// 不良示例 - 避免此类模式
const result: any = someOperation();
const value = maybeUndefined!;
const data = response as unknown as MyType;

// 良好示例 - 使用此类模式
type EntitySlug = string & { readonly __brand: unique symbol };
const isSlugBasedEntity = (entity: unknown): entity is { slug: string } => { ... };
const ENTITY_TYPES = ['categories', 'products'] as const;

// 良好示例 - 使用satisfies进行类型验证,同时保留字面量类型
interface ConfigShape {
  readonly MAX_ITEMS: number;
  readonly TIMEOUT: number;
}
const CONFIG = {
  MAX_ITEMS: 10,
  TIMEOUT: 5000,
} as const satisfies ConfigShape;
// CONFIG.MAX_ITEMS的类型为`10`,而非仅`number`

// 良好示例 - 使用satisfies验证模板字面量类型
type CliFlag = `--${string}`;
const FLAGS = ["--json", "--verbose"] as const satisfies readonly CliFlag[];

2. Clean Code Principles

2. 整洁代码原则

Function Quality:
  • Single Responsibility Principle followed
  • Functions are small (< 20 lines ideally)
  • Pure functions where possible (no side effects)
  • Meaningful, declarative names used
  • Arrow functions for consistency
Naming Conventions:
  • Functions describe what they do, not how
  • Variables are descriptive and context-specific
  • Boolean names start with
    is
    ,
    has
    ,
    should
    ,
    can
  • Collections use plural names
DRY (Don't Repeat Yourself):
  • Shared utilities extracted to dedicated modules
  • Magic numbers replaced with named constants
  • Repeated logic extracted to helper functions
  • Constants grouped in config objects
Registry Pattern for Conditionals:
  • Long if-else chains refactored to registry/strategy pattern
  • Error classification uses matcher registry
  • Type dispatch uses discriminated unions or maps
typescript
// BAD naming
const data = process(items);
const flag = check(user);

// GOOD naming
const categoriesToProcess = await fetchPendingCategories();
const isEntitySlugUnique = await validateSlugUniqueness(slug);

// BAD - Magic numbers
if (items.length > 10) { truncate(); }
const preview = text.slice(0, 30);

// GOOD - Named constants
const LIMITS = { MAX_ITEMS: 10, MAX_PREVIEW: 30 } as const;
if (items.length > LIMITS.MAX_ITEMS) { truncate(); }
const preview = text.slice(0, LIMITS.MAX_PREVIEW);

// BAD - Long if-else chain
function classify(error: Error): AppError {
  if (error.message.includes("network")) return new NetworkError();
  if (error.message.includes("auth")) return new AuthError();
  if (error.message.includes("validation")) return new ValidationError();
  return new UnexpectedError();
}

// GOOD - Registry pattern
interface ErrorMatcher {
  matches: (msg: string) => boolean;
  create: (error: Error) => AppError;
}
const ERROR_MATCHERS: ErrorMatcher[] = [
  { matches: (m) => m.includes("network"), create: () => new NetworkError() },
  { matches: (m) => m.includes("auth"), create: () => new AuthError() },
];
function classify(error: Error): AppError {
  const matcher = ERROR_MATCHERS.find((m) => m.matches(error.message));
  return matcher?.create(error) ?? new UnexpectedError();
}
函数质量:
  • 遵循单一职责原则
  • 函数体量小(理想情况下少于20行)
  • 尽可能使用纯函数(无副作用)
  • 使用有意义的声明式命名
  • 统一使用箭头函数
命名规范:
  • 函数名称描述做什么,而非怎么做
  • 变量名称具有描述性且贴合上下文
  • 布尔值名称以
    is
    has
    should
    can
    开头
  • 集合使用复数名称
DRY原则(避免重复):
  • 将共享工具提取到专用模块
  • 使用命名常量替代魔法数值
  • 将重复逻辑提取到辅助函数
  • 常量分组到配置对象中
条件判断的注册表模式:
  • 将长if-else链重构为注册表/策略模式
  • 错误分类使用匹配器注册表
  • 类型分发使用可区分联合或映射
typescript
// 不良命名示例
const data = process(items);
const flag = check(user);

// 良好命名示例
const categoriesToProcess = await fetchPendingCategories();
const isEntitySlugUnique = await validateSlugUniqueness(slug);

// 不良示例 - 魔法数值
if (items.length > 10) { truncate(); }
const preview = text.slice(0, 30);

// 良好示例 - 命名常量
const LIMITS = { MAX_ITEMS: 10, MAX_PREVIEW: 30 } as const;
if (items.length > LIMITS.MAX_ITEMS) { truncate(); }
const preview = text.slice(0, LIMITS.MAX_PREVIEW);

// 不良示例 - 长if-else链
function classify(error: Error): AppError {
  if (error.message.includes("network")) return new NetworkError();
  if (error.message.includes("auth")) return new AuthError();
  if (error.message.includes("validation")) return new ValidationError();
  return new UnexpectedError();
}

// 良好示例 - 注册表模式
interface ErrorMatcher {
  matches: (msg: string) => boolean;
  create: (error: Error) => AppError;
}
const ERROR_MATCHERS: ErrorMatcher[] = [
  { matches: (m) => m.includes("network"), create: () => new NetworkError() },
  { matches: (m) => m.includes("auth"), create: () => new AuthError() },
];
function classify(error: Error): AppError {
  const matcher = ERROR_MATCHERS.find((m) => m.matches(error.message));
  return matcher?.create(error) ?? new UnexpectedError();
}

3. Functional Programming Patterns

3. 函数式编程模式

Immutability:
  • No direct mutation of arrays or objects
  • Spread operator or immutable methods used
  • Map
    preferred over object for frequent lookups
Composition:
  • Small, composable functions
  • Higher-order functions for reusable logic
  • Pipeline patterns where appropriate
Imperative to Functional Refactoring:
  • for
    loops replaced with
    map
    /
    filter
    /
    reduce
  • forEach
    with push replaced with spread +
    map
  • Nested loops replaced with
    flatMap
  • Conditional accumulation uses
    map
    +
    filter
    with type guards
typescript
// BAD - Mutation
items.push(newItem);
entity.status = 'active';

// GOOD - Immutable
const updatedItems = [...items, newItem];
const updatedEntity = { ...entity, status: 'active' };

// BAD - Imperative loop with push
const lines: string[] = [];
for (const item of items) {
  lines.push(formatItem(item));
}

// GOOD - Functional map
const lines = items.map(formatItem);

// BAD - forEach with conditional push
const results: Result[] = [];
items.forEach((item) => {
  const match = item.match(regex);
  if (match) {
    results.push({ id: match[1] });
  }
});

// GOOD - map + filter with type guard
const results = items
  .map((item) => {
    const match = item.match(regex);
    return match ? { id: match[1] } : null;
  })
  .filter((r): r is Result => r !== null);

// BAD - Nested forEach
items.forEach((item) => {
  lines.push(`Name: ${item.name}`);
  item.details.forEach((d) => lines.push(`  - ${d}`));
});

// GOOD - flatMap for nested structures
const lines = items.flatMap((item) => [
  `Name: ${item.name}`,
  ...item.details.map((d) => `  - ${d}`),
]);
不可变性:
  • 不直接修改数组或对象
  • 使用扩展运算符或不可变方法
  • 频繁查找时优先使用
    Map
    而非对象
组合:
  • 小而可组合的函数
  • 使用高阶函数实现可复用逻辑
  • 适当使用管道模式
命令式到函数式重构:
  • 使用
    map
    /
    filter
    /
    reduce
    替代
    for
    循环
  • 使用扩展运算符+
    map
    替代带push的
    forEach
  • 使用
    flatMap
    替代嵌套循环
  • 条件累加使用
    map
    +
    filter
    结合类型守卫
typescript
// 不良示例 - 直接修改
items.push(newItem);
entity.status = 'active';

// 良好示例 - 不可变操作
const updatedItems = [...items, newItem];
const updatedEntity = { ...entity, status: 'active' };

// 不良示例 - 命令式循环+push
const lines: string[] = [];
for (const item of items) {
  lines.push(formatItem(item));
}

// 良好示例 - 函数式map
const lines = items.map(formatItem);

// 不良示例 - 带条件push的forEach
const results: Result[] = [];
items.forEach((item) => {
  const match = item.match(regex);
  if (match) {
    results.push({ id: match[1] });
  }
});

// 良好示例 - map+filter结合类型守卫
const results = items
  .map((item) => {
    const match = item.match(regex);
    return match ? { id: match[1] } : null;
  })
  .filter((r): r is Result => r !== null);

// 不良示例 - 嵌套forEach
items.forEach((item) => {
  lines.push(`Name: ${item.name}`);
  item.details.forEach((d) => lines.push(`  - ${d}`));
});

// 良好示例 - 使用flatMap处理嵌套结构
const lines = items.flatMap((item) => [
  `Name: ${item.name}`,
  ...item.details.map((d) => `  - ${d}`),
]);

4. Zod Schema Usage

4. Zod模式使用

Schema Patterns:
  • Schemas defined before implementing logic
  • Type inference with
    z.infer<>
  • Reusable schema primitives (EntitySlugSchema, EntityNameSchema)
  • Discriminated unions for variant types
  • Transform and refinement used appropriately
Validation:
  • safeParse
    for error handling
  • Detailed error messages with context
  • Schema reuse in tests
typescript
// GOOD pattern
const CategorySchema = BaseEntitySchema.extend({
  slug: EntitySlugSchema,
  parent: EntitySlugSchema.optional(),
});

type CategoryInput = z.infer<typeof CategorySchema>;
模式设计:
  • 在实现逻辑前定义模式
  • 使用
    z.infer<>
    进行类型推断
  • 可复用的模式原语(EntitySlugSchema、EntityNameSchema)
  • 为变体类型使用可区分联合
  • 适当使用转换和细化
验证:
  • 使用
    safeParse
    进行错误处理
  • 提供带上下文的详细错误信息
  • 在测试中复用模式
typescript
// 良好示例
const CategorySchema = BaseEntitySchema.extend({
  slug: EntitySlugSchema,
  parent: EntitySlugSchema.optional(),
});

type CategoryInput = z.infer<typeof CategorySchema>;

5. Error Handling

5. 错误处理

Error Types:
  • Specific error types extend
    BaseError
  • GraphQL errors wrapped with
    GraphQLError.fromCombinedError()
  • Zod errors wrapped with
    ZodValidationError.fromZodError()
  • Error messages are actionable
Error Design:
  • Error includes relevant context
  • Recovery suggestions provided
  • Error codes for machine processing
typescript
// GOOD error pattern
class EntityValidationError extends BaseError {
  constructor(message: string, public readonly validationIssues: ValidationIssue[] = []) {
    super(message, 'ENTITY_VALIDATION_ERROR');
  }

  getSuggestions(): string[] {
    return ['Check entity configuration against schema'];
  }
}
错误类型:
  • 特定错误类型继承自
    BaseError
  • 使用
    GraphQLError.fromCombinedError()
    包裹GraphQL错误
  • 使用
    ZodValidationError.fromZodError()
    包裹Zod错误
  • 错误消息具有可操作性
错误设计:
  • 错误包含相关上下文
  • 提供恢复建议
  • 为机器处理提供错误码
typescript
// 良好错误示例
class EntityValidationError extends BaseError {
  constructor(message: string, public readonly validationIssues: ValidationIssue[] = []) {
    super(message, 'ENTITY_VALIDATION_ERROR');
  }

  getSuggestions(): string[] {
    return ['检查实体配置是否符合模式要求'];
  }
}

6. Performance Considerations

6. 性能考量

Avoid Anti-patterns:
  • No accumulating spreads in reduce
  • No function creation in loops
  • No unnecessary object creation
Optimize:
  • Use
    Map
    for frequent lookups
  • Lazy evaluation for expensive operations
  • Memoization where appropriate
typescript
// BAD - Creates new object each iteration
const result = items.reduce((acc, item) => ({ ...acc, [item.id]: item }), {});

// GOOD - Mutates Map directly
const result = items.reduce((acc, item) => acc.set(item.id, item), new Map());
避免反模式:
  • 不在reduce中使用累积扩展运算符
  • 不在循环中创建函数
  • 不进行不必要的对象创建
优化建议:
  • 频繁查找时使用
    Map
  • 对昂贵操作使用延迟求值
  • 适当使用记忆化
typescript
// 不良示例 - 每次迭代创建新对象
const result = items.reduce((acc, item) => ({ ...acc, [item.id]: item }), {});

// 良好示例 - 直接修改Map
const result = items.reduce((acc, item) => acc.set(item.id, item), new Map());

Review Output Format

评审输出格式

Structure findings as:
按以下结构整理发现的问题:

Critical Issues

关键问题

Items that must be fixed before merge.
合并前必须修复的项。

Important Improvements

重要改进

Items that should be addressed but aren't blocking.
应处理但不阻塞合并的项。

Suggestions

建议

Nice-to-have improvements for future consideration.
未来可考虑的优化项。

Positive Observations

正向观察

Well-implemented patterns worth highlighting.
值得强调的良好实现模式。

Project-Specific Conventions

项目特定规范

  • Entity identification: Slug-based (categories, products) vs Name-based (productTypes, pageTypes)
  • Service pattern: Constructor DI with validator, repository, logger
  • Repository pattern: GraphQL operations encapsulated
  • Test pattern: vi.fn() mocks with schema-generated test data
  • 实体标识:基于Slug(类目、商品) vs 基于名称(productTypes、pageTypes)
  • 服务模式:构造函数依赖注入,包含验证器、仓库、日志器
  • 仓库模式:封装GraphQL操作
  • 测试模式:使用vi.fn()模拟,结合模式生成的测试数据

References

参考资料

Skill Reference Files

技能参考文件

  • Anti-Patterns - Common anti-patterns with corrections
  • Type Safety Examples - Type guards, branded types, discriminated unions
  • 反模式 - 常见反模式及修正方案
  • 类型安全示例 - 类型守卫、品牌类型、可区分联合

Project Resources

项目资源

  • See
    {baseDir}/docs/CODE_QUALITY.md
    for complete coding standards
  • See
    {baseDir}/docs/ARCHITECTURE.md
    for service patterns
  • See
    {baseDir}/biome.json
    for linting rules
  • 完整编码规范请查看
    {baseDir}/docs/CODE_QUALITY.md
  • 服务模式请查看
    {baseDir}/docs/ARCHITECTURE.md
  • linting规则请查看
    {baseDir}/biome.json

Related Skills

相关技能

  • Complete entity workflow: See
    adding-entity-types
    for architectural patterns
  • Zod standards: See
    designing-zod-schemas
    for schema review criteria
  • Pre-commit checks: See
    validating-pre-commit
    for quality gate commands
  • 完整实体工作流:查看
    adding-entity-types
    获取架构模式
  • Zod标准:查看
    designing-zod-schemas
    获取模式评审标准
  • 提交前检查:查看
    validating-pre-commit
    获取质量门禁命令

Quick Reference Rule

快速参考规则

For a condensed quick reference, see
.claude/rules/code-quality.md
(automatically loaded when editing
src/**/*.ts
files).
如需精简版快速参考,请查看
.claude/rules/code-quality.md
(编辑
src/**/*.ts
文件时自动加载)。