enforcing-typescript-standards

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Enforcing TypeScript Standards

强制执行TypeScript标准

Enforces the project's core TypeScript standards including explicit typing, import organization, class member ordering, and code safety rules.
强制执行项目的核心TypeScript标准,包括显式类型定义、导入组织、类成员排序和代码安全规则。

Triggers

触发场景

Activate this skill when the user says or implies any of these:
  • "write", "create", "implement", "add", "build" (new TypeScript code)
  • "fix", "update", "change", "modify", "refactor" (existing TypeScript code)
  • "review", "check", "improve", "clean up" (code quality)
  • Any request involving
    .ts
    or
    .tsx
    files
Specific triggers:
  • Creating a new
    .ts
    or
    .tsx
    file
  • Modifying existing TypeScript code
  • Reviewing TypeScript code for compliance
当用户提及或暗示以下内容时,启用此规范:
  • "编写"、"创建"、"实现"、"添加"、"构建"(新的TypeScript代码)
  • "修复"、"更新"、"更改"、"修改"、"重构"(现有TypeScript代码)
  • "审查"、"检查"、"改进"、"清理"(代码质量)
  • 任何涉及.ts或.tsx文件的请求
具体触发场景:
  • 创建新的.ts或.tsx文件
  • 修改现有TypeScript代码
  • 审查TypeScript代码是否符合规范

Core Standards

核心标准

Type Safety

类型安全

  • Explicit return types: Prefer explicit return types when practical; omit when inference is obvious and adds no clarity
  • Explicit member accessibility: Class members require
    public
    ,
    private
    , or
    protected
  • Type-only imports: Use
    import type
    for types:
    import type { Foo } from './foo.js'
  • Sorted type constituents: Union/intersection types must be alphabetically sorted
  • Only throw Error objects: Never throw strings or other primitives
  • Avoid
    any
    and type assertions
    : Prefer proper typing over
    any
    or
    as
    casts; use them only when truly necessary
  • Type JSON fields explicitly: Use
    Record<string, unknown>
    or specific interfaces for JSON data, never
    any
  • Use Number() for conversion: Prefer
    Number(value)
    over
    parseInt(value, 10)
    or
    parseFloat(value)
  • Reuse existing types: Before defining a new interface, search for existing types that can be reused directly, extended, or derived using
    Pick
    ,
    Omit
    ,
    Partial
    , or other utility types
  • 显式返回类型:在实际可行时优先使用显式返回类型;当类型推断明显且不会降低可读性时可省略
  • 显式成员访问修饰符:类成员必须指定
    public
    private
    protected
  • 仅类型导入:使用
    import type
    导入类型:
    import type { Foo } from './foo.js'
  • 排序类型组成:联合/交叉类型必须按字母顺序排序
  • 仅抛出Error对象:永远不要抛出字符串或其他原始类型
  • 避免
    any
    和类型断言
    :优先使用正确的类型定义,而非
    any
    as
    类型转换;仅在绝对必要时使用它们
  • 显式类型化JSON字段:对JSON数据使用
    Record<string, unknown>
    或特定接口,绝不要使用
    any
  • 使用Number()进行转换:优先使用
    Number(value)
    而非
    parseInt(value, 10)
    parseFloat(value)
  • 复用现有类型:在定义新接口之前,搜索可直接复用、扩展或通过
    Pick
    Omit
    Partial
    等工具类型派生的现有类型

Alternatives to Type Assertions

类型断言的替代方案

Before using
as
, try these approaches in order:
  1. Proper typing at the source
  2. Type guards (
    typeof
    ,
    instanceof
    )
  3. Type narrowing through control flow
  4. Custom type predicate functions
  5. Discriminated unions
ts
// Bad
const user = data as User;

// Good
function isUser(data: unknown): data is User {
  return typeof data === 'object' && data !== null && 'id' in data;
}
if (isUser(data)) {
  // data is now typed as User
}
在使用
as
之前,按以下顺序尝试这些方法:
  1. 在数据源处进行正确的类型定义
  2. 类型守卫(
    typeof
    instanceof
  3. 通过控制流缩小类型范围
  4. 自定义类型谓词函数
  5. 可辨识联合类型
ts
// 不良示例
const user = data as User;

// 良好示例
function isUser(data: unknown): data is User {
  return typeof data === 'object' && data !== null && 'id' in data;
}
if (isUser(data)) {
  // 此时data的类型为User
}

Import Organization

导入组织

  • Import order: builtin → external → internal → parent → sibling → index (alphabetized within groups)
  • No duplicate imports: Consolidate imports from the same module
  • Newline after imports: Blank line required after import block
  • 导入顺序:内置模块 → 外部模块 → 内部模块 → 父级模块 → 同级模块 → 索引模块(每组内按字母顺序排序)
  • 无重复导入:合并来自同一模块的导入
  • 导入后换行:导入块后必须留空行

Class Member Ordering

类成员排序

  1. Signatures (call/construct)
  2. Fields: private → public → protected
  3. Constructors: public → protected → private
  4. Methods: public → protected → private
  1. 签名(调用/构造函数)
  2. 字段:private → public → protected
  3. 构造函数:public → protected → private
  4. 方法:public → protected → private

Code Style

代码风格

  • Simplicity over cleverness: Straightforward, readable code is better than clever one-liners
  • Early returns: Use guard clauses to reduce nesting; return early for edge cases
  • Nullish coalescing: Prefer
    ??
    over
    ||
    for defaults (avoids false positives on
    0
    or
    ''
    )
  • Optional chaining: Use
    ?.
    for safe property access
  • Match existing patterns: Follow conventions already established in the codebase
  • Meaningful identifiers: Names must be descriptive (exceptions:
    _
    ,
    i
    ,
    j
    ,
    k
    ,
    e
    ,
    x
    ,
    y
    )
  • Function declarations: Use
    function foo()
    not
    const foo = function()
  • Prefer const: Use
    const
    unless reassignment is needed
  • No var: Always use
    const
    or
    let
  • Object shorthand: Use
    { foo }
    not
    { foo: foo }
  • Template literals: Use
    `Hello ${name}`
    not
    'Hello ' + name
  • Strict equality: Use
    ===
    except for null comparisons
  • One class per file: Maximum one class definition per file
  • Avoid
    reduce
    : Prefer
    for...of
    loops or other array methods for clarity
  • Functions over classes: Prefer exported functions over classes with static methods (unless state is needed)
  • No nested functions: Define helper functions at module level, not inside other functions
  • Immutability: Create new objects/arrays instead of mutating existing ones
  • 简洁胜于技巧:直接、可读的代码优于巧妙的单行代码
  • 提前返回:使用守卫语句减少嵌套;对边缘情况提前返回
  • 空值合并运算符:优先使用
    ??
    而非
    ||
    设置默认值(避免将
    0
    ''
    误判为假值)
  • 可选链运算符:使用
    ?.
    进行安全的属性访问
  • 匹配现有模式:遵循代码库中已确立的约定
  • 有意义的标识符:名称必须具有描述性(例外:
    _
    i
    j
    k
    e
    x
    y
  • 函数声明:使用
    function foo()
    而非
    const foo = function()
  • 优先使用const:除非需要重新赋值,否则使用
    const
  • 禁止使用var:始终使用
    const
    let
  • 对象简写:使用
    { foo }
    而非
    { foo: foo }
  • 模板字符串:使用
    `Hello ${name}`
    而非
    'Hello ' + name
  • 严格相等:除了null比较外,使用
    ===
  • 每个文件一个类:每个文件最多定义一个类
  • 避免使用reduce:为了清晰,优先使用
    for...of
    循环或其他数组方法
  • 优先使用函数而非类:优先使用导出函数而非仅含静态方法的类(除非需要维护状态)
  • 禁止嵌套函数:在模块级别定义辅助函数,而非在其他函数内部
  • 不可变性:创建新的对象/数组,而非修改现有对象/数组

Naming Conventions

命名约定

  • Enum members: Use
    PascalCase
    (e.g.,
    MyValue
    )
  • No trailing underscores: Identifiers cannot end with
    _
  • 枚举成员:使用
    PascalCase
    (例如:
    MyValue
  • 禁止尾随下划线:标识符不能以下划线
    _
    结尾

Comments

注释

  • No redundant comments: Never comment what the code already expresses clearly
  • No duplicate comments: Don't repeat information from function names, types, or nearby comments
  • Meaningful only: Only add comments to explain why, not what — the code shows what it does
  • 无冗余注释:永远不要注释代码已清晰表达的内容
  • 无重复注释:不要重复函数名、类型或附近注释中的信息
  • 仅添加有意义的注释:仅添加注释解释_为什么_,而非_做什么_——代码本身会展示它的功能

Boolean Expressions

布尔表达式

  • Prefer truthiness checks: Use implicit truthy/falsy checks over explicit comparisons
  • Exception: Use explicit checks when distinguishing
    0
    /
    ''
    (valid values) from
    null
    /
    undefined
    is semantically important
  • 优先使用真值检查:使用隐式真值/假值检查而非显式比较
  • 例外情况:当在语义上需要区分
    0
    /
    ''
    (有效值)与
    null
    /
    undefined
    时,使用显式检查

Testing

测试

  • Minimize mocking: Avoid mocking everything; use real implementations and data generators when available
  • Test real behavior: Testing mocks provides little value — test actual code paths
  • Don't be lazy: Write thorough tests that cover edge cases, not just happy paths
  • 最小化模拟:避免模拟所有内容;在可用时使用真实实现和数据生成器
  • 测试真实行为:模拟测试几乎没有价值——测试实际的代码路径
  • 不要偷懒:编写全面的测试,覆盖边缘情况,而不仅仅是正常路径

Error Handling

错误处理

  • Specific error types: Prefer specific error types over generic
    Error
    when meaningful
  • Avoid silent failures: Don't swallow errors with empty catch blocks
  • Handle rejections: Always handle promise rejections
  • Let errors propagate: Don't catch errors just to re-throw or log — let them bubble up to error handlers
  • 特定错误类型:在有意义时优先使用特定错误类型而非通用
    Error
  • 避免静默失败:不要用空的catch块吞噬错误
  • 处理拒绝:始终处理Promise的拒绝
  • 让错误传播:不要为了重新抛出或记录而捕获错误——让它们冒泡到错误处理程序

Negative Knowledge

反模式规避

Avoid these anti-patterns:
  • console.log()
    statements in production code
  • eval()
    or
    Function()
    constructor
  • Nested ternary operators
  • await
    inside loops when
    Promise.all
    would be simpler (sequential awaits are fine when order matters or parallelism adds complexity)
  • Empty interfaces
  • Variable shadowing
  • Functions defined inside loops
  • @ts-ignore
    without explanation (use
    @ts-expect-error
    with 10+ char description)
  • Comments that restate the code:
    // increment counter
    above
    counter++
  • Comments that duplicate type information:
    // returns a string
    when return type is
    : string
  • Commented-out code (delete it; use version control)
  • Verbose boolean comparisons:
    arr.length > 0
    ,
    str !== ''
    ,
    obj !== null && obj !== undefined
  • Disabling lint rules via comments (fix the code instead)
  • Overuse of
    any
    type or
    as
    type assertions
  • Over-mocking in tests instead of using real implementations or data generators
  • Empty catch blocks that silently swallow errors
  • Using
    ||
    for defaults when
    ??
    is more appropriate
  • Deep nesting when early returns would simplify
  • Catching errors just to re-throw or log them
  • Nested function definitions inside other functions
  • Mutating objects/arrays instead of creating new ones
  • TOCTOU: Checking file/resource existence before operating (try and handle errors instead)
  • Classes with only static methods (use plain functions instead)
  • Duplicating existing interfaces instead of reusing or deriving with
    Pick
    /
    Omit
    /
    Partial
避免以下不良实践:
  • 生产代码中的
    console.log()
    语句
  • eval()
    Function()
    构造函数
  • 嵌套三元运算符
  • Promise.all
    更简单时在循环内使用
    await
    (当顺序重要或并行处理增加复杂度时,顺序
    await
    是可以的)
  • 空接口
  • 变量遮蔽
  • 在循环内定义函数
  • 无解释的
    @ts-ignore
    (使用带有10个字符以上描述的
    @ts-expect-error
  • 重复代码的注释:
    // increment counter
    放在
    counter++
    上方
  • 重复类型信息的注释:当返回类型为
    : string
    时,不要写
    // returns a string
  • 被注释掉的代码(删除它;使用版本控制)
  • 冗长的布尔比较:
    arr.length > 0
    str !== ''
    obj !== null && obj !== undefined
  • 通过注释禁用lint规则(修复代码代替)
  • 过度使用
    any
    类型或
    as
    类型断言
  • 测试中过度模拟而非使用真实实现或数据生成器
  • 吞噬错误的空catch块
  • ??
    更合适时使用
    ||
    设置默认值
  • 当提前返回可以简化时使用深层嵌套
  • 仅为了重新抛出或记录而捕获错误
  • 在其他函数内部定义嵌套函数
  • 修改现有对象/数组而非创建新对象/数组
  • TOCTOU:在操作前检查文件/资源是否存在(尝试操作并处理错误代替)
  • 仅含静态方法的类(改用普通函数)
  • 重复现有接口而非复用或通过
    Pick
    /
    Omit
    /
    Partial
    派生

Verification Workflow

验证流程

  1. Analyze: Compare the code change against these TypeScript standards
  2. Generate/Refactor: Write or modify code to comply with all rules above
  3. Simplify: Review for opportunities to simplify — prefer clear, straightforward code over clever solutions
  4. Review naming: Verify variable and function names still make sense in context after changes
  5. Build: Verify types compile without errors (e.g.,
    npm run build
    or
    npx tsc --noEmit
    )
  6. Lint: Run
    npm run lint
    to confirm compliance before completing the task
  1. 分析:将代码变更与这些TypeScript标准进行比较
  2. 生成/重构:编写或修改代码以符合上述所有规则
  3. 简化:审查简化的机会——优先选择清晰、直接的代码而非巧妙的解决方案
  4. 审查命名:验证变量和函数名在变更后的上下文中仍然有意义
  5. 构建:验证类型编译无错误(例如:
    npm run build
    npx tsc --noEmit
  6. Lint检查:在完成任务前运行
    npm run lint
    确认符合规范

Examples

示例

Comments Examples

注释示例

ts
// Standard
// Retry with exponential backoff to handle transient network failures
async function fetchWithRetry(url: string, attempts = 3): Promise<Response> {
  for (let i = 0; i < attempts; i++) {
    try {
      return await fetch(url);
    } catch {
      await sleep(2 ** i * 100);
    }
  }
  throw new Error(`Failed after ${attempts} attempts`);
}

// Non-Standard
/**
 * Fetches data from a URL with retry logic
 * @param url - The URL to fetch from
 * @param attempts - Number of attempts (default 3)
 * @returns A Promise that resolves to a Response
 */
async function fetchWithRetry(url: string, attempts = 3): Promise<Response> {
  // Loop through attempts
  for (let i = 0; i < attempts; i++) {
    try {
      // Try to fetch the URL
      return await fetch(url);
    } catch {
      // Wait before retrying
      await sleep(2 ** i * 100);
    }
  }
  // Throw error if all attempts fail
  throw new Error(`Failed after ${attempts} attempts`);
}
ts
// 标准示例
// 使用指数退避重试以处理临时网络故障
async function fetchWithRetry(url: string, attempts = 3): Promise<Response> {
  for (let i = 0; i < attempts; i++) {
    try {
      return await fetch(url);
    } catch {
      await sleep(2 ** i * 100);
    }
  }
  throw new Error(`Failed after ${attempts} attempts`);
}

// 非标准示例
/**
 * 带重试逻辑的URL数据获取
 * @param url - 要获取的URL
 * @param attempts - 尝试次数(默认3次)
 * @returns 解析为Response的Promise
 */
async function fetchWithRetry(url: string, attempts = 3): Promise<Response> {
  // 循环尝试
  for (let i = 0; i < attempts; i++) {
    try {
      // 尝试获取URL
      return await fetch(url);
    } catch {
      // 重试前等待
      await sleep(2 ** i * 100);
    }
  }
  // 所有尝试失败时抛出错误
  throw new Error(`Failed after ${attempts} attempts`);
}

Boolean Expressions Examples

布尔表达式示例

ts
// Standard
if (myArray.length) {
}
if (myString) {
}
if (myObject) {
}
if (!value) {
}

// Non-Standard
if (myArray.length !== 0) {
}
if (myArray.length > 0) {
}
if (myString !== '') {
}
if (myObject !== null && myObject !== undefined) {
}
if (value === null || value === undefined) {
}
ts
// 标准示例
if (myArray.length) {
}
if (myString) {
}
if (myObject) {
}
if (!value) {
}

// 非标准示例
if (myArray.length !== 0) {
}
if (myArray.length > 0) {
}
if (myString !== '') {
}
if (myObject !== null && myObject !== undefined) {
}
if (value === null || value === undefined) {
}

Early Return Examples

提前返回示例

ts
// Standard
function processUser(user: User | null): Result {
  if (!user) {
    return { error: 'No user provided' };
  }
  if (!user.isActive) {
    return { error: 'User is inactive' };
  }
  return { data: transform(user) };
}

// Non-Standard
function processUser(user: User | null): Result {
  if (user) {
    if (user.isActive) {
      return { data: transform(user) };
    } else {
      return { error: 'User is inactive' };
    }
  } else {
    return { error: 'No user provided' };
  }
}
ts
// 标准示例
function processUser(user: User | null): Result {
  if (!user) {
    return { error: '未提供用户' };
  }
  if (!user.isActive) {
    return { error: '用户已失效' };
  }
  return { data: transform(user) };
}

// 非标准示例
function processUser(user: User | null): Result {
  if (user) {
    if (user.isActive) {
      return { data: transform(user) };
    } else {
      return { error: '用户已失效' };
    }
  } else {
    return { error: '未提供用户' };
  }
}

Functions Over Classes Examples

优先使用函数而非类示例

ts
// Standard
export function calculateTotal(items: Item[]): number {
  return items.reduce((sum, item) => sum + item.price, 0);
}

export function formatCurrency(amount: number): string {
  return `$${amount.toFixed(2)}`;
}

// Non-Standard
export class Calculator {
  static calculateTotal(items: Item[]): number {
    return items.reduce((sum, item) => sum + item.price, 0);
  }

  static formatCurrency(amount: number): string {
    return `$${amount.toFixed(2)}`;
  }
}
ts
// 标准示例
export function calculateTotal(items: Item[]): number {
  return items.reduce((sum, item) => sum + item.price, 0);
}

export function formatCurrency(amount: number): string {
  return `$${amount.toFixed(2)}`;
}

// 非标准示例
export class Calculator {
  static calculateTotal(items: Item[]): number {
    return items.reduce((sum, item) => sum + item.price, 0);
  }

  static formatCurrency(amount: number): string {
    return `$${amount.toFixed(2)}`;
  }
}

No Nested Functions Examples

禁止嵌套函数示例

ts
// Standard
function transformItem(item: Item): TransformedItem {
  return { id: item.id, name: item.name.toUpperCase() };
}

async function processItems(items: Item[]): Promise<TransformedItem[]> {
  return items.map(transformItem);
}

// Non-Standard
async function processItems(items: Item[]): Promise<TransformedItem[]> {
  function transformItem(item: Item): TransformedItem {
    return { id: item.id, name: item.name.toUpperCase() };
  }
  return items.map(transformItem);
}
ts
// 标准示例
function transformItem(item: Item): TransformedItem {
  return { id: item.id, name: item.name.toUpperCase() };
}

async function processItems(items: Item[]): Promise<TransformedItem[]> {
  return items.map(transformItem);
}

// 非标准示例
async function processItems(items: Item[]): Promise<TransformedItem[]> {
  function transformItem(item: Item): TransformedItem {
    return { id: item.id, name: item.name.toUpperCase() };
  }
  return items.map(transformItem);
}

Immutability Examples

不可变性示例

ts
// Standard
function addItem(items: Item[], newItem: Item): Item[] {
  return [...items, newItem];
}

function removeItem(items: Item[], id: string): Item[] {
  return items.filter((item) => item.id !== id);
}

function updateItem(items: Item[], id: string, updates: Partial<Item>): Item[] {
  return items.map((item) => (item.id === id ? { ...item, ...updates } : item));
}

// Non-Standard
function addItem(items: Item[], newItem: Item): Item[] {
  items.push(newItem);
  return items;
}

function removeItem(items: Item[], id: string): Item[] {
  const index = items.findIndex((item) => item.id === id);
  items.splice(index, 1);
  return items;
}
ts
// 标准示例
function addItem(items: Item[], newItem: Item): Item[] {
  return [...items, newItem];
}

function removeItem(items: Item[], id: string): Item[] {
  return items.filter((item) => item.id !== id);
}

function updateItem(items: Item[], id: string, updates: Partial<Item>): Item[] {
  return items.map((item) => (item.id === id ? { ...item, ...updates } : item));
}

// 非标准示例
function addItem(items: Item[], newItem: Item): Item[] {
  items.push(newItem);
  return items;
}

function removeItem(items: Item[], id: string): Item[] {
  const index = items.findIndex((item) => item.id === id);
  items.splice(index, 1);
  return items;
}

Error Propagation Examples

错误传播示例

ts
// Standard
async function getUser(id: string): Promise<User> {
  return userService.findById(id);
}

// Non-Standard
async function getUser(id: string): Promise<User> {
  try {
    return await userService.findById(id);
  } catch (error) {
    console.error(error);
    throw error;
  }
}
ts
// 标准示例
async function getUser(id: string): Promise<User> {
  return userService.findById(id);
}

// 非标准示例
async function getUser(id: string): Promise<User> {
  try {
    return await userService.findById(id);
  } catch (error) {
    console.error(error);
    throw error;
  }
}

TOCTOU Examples

TOCTOU示例

ts
// Standard
async function readConfig(path: string): Promise<Config> {
  try {
    const content = await readFile(path, 'utf-8');
    return JSON.parse(content);
  } catch (error) {
    if (isNotFoundError(error)) {
      return defaultConfig;
    }
    throw error;
  }
}

// Non-Standard
async function readConfig(path: string): Promise<Config> {
  if (await fileExists(path)) {
    const content = await readFile(path, 'utf-8');
    return JSON.parse(content);
  }
  return defaultConfig;
}
ts
// 标准示例
async function readConfig(path: string): Promise<Config> {
  try {
    const content = await readFile(path, 'utf-8');
    return JSON.parse(content);
  } catch (error) {
    if (isNotFoundError(error)) {
      return defaultConfig;
    }
    throw error;
  }
}

// 非标准示例
async function readConfig(path: string): Promise<Config> {
  if (await fileExists(path)) {
    const content = await readFile(path, 'utf-8');
    return JSON.parse(content);
  }
  return defaultConfig;
}

Type Reuse Examples

类型复用示例

ts
// Given an existing type
interface User {
  id: string;
  email: string;
  name: string;
  passwordHash: string;
  createdAt: Date;
  updatedAt: Date;
}

// Standard - derive from existing type
type PublicUser = Omit<User, 'passwordHash'>;
type UserSummary = Pick<User, 'id' | 'name'>;
type UserUpdate = Partial<Pick<User, 'email' | 'name'>>;

// Non-Standard - duplicating fields that already exist
interface PublicUser {
  id: string;
  email: string;
  name: string;
  createdAt: Date;
  updatedAt: Date;
}

interface UserSummary {
  id: string;
  name: string;
}

interface UserUpdate {
  email?: string;
  name?: string;
}
ts
// 给定现有类型
interface User {
  id: string;
  email: string;
  name: string;
  passwordHash: string;
  createdAt: Date;
  updatedAt: Date;
}

// 标准示例 - 从现有类型派生
type PublicUser = Omit<User, 'passwordHash'>;
type UserSummary = Pick<User, 'id' | 'name'>;
type UserUpdate = Partial<Pick<User, 'email' | 'name'>>;

// 非标准示例 - 重复已存在的字段
interface PublicUser {
  id: string;
  email: string;
  name: string;
  createdAt: Date;
  updatedAt: Date;
}

interface UserSummary {
  id: string;
  name: string;
}

interface UserUpdate {
  email?: string;
  name?: string;
}