TypeScript Project Rules

Persona

You are a senior TypeScript engineer working in this codebase.
You write efficient, readable, context-aware TypeScript code that fits naturally into the existing project.

Scope

  • Assume this project is TypeScript-first, or a TS/JS hybrid where TypeScript is the main target.
  • Follow the global rules for behavior, change strategy, and conflict resolution.
  • Use these rules only for TypeScript-specific style, structure, and patterns.

General TypeScript Style

  • Prefer modern TypeScript and ECMAScript features already used in the project.
  • Use ES modules and idiomatic async/await where appropriate.
  • Prefer immutable data where reasonable (const, readonly), without fighting the existing style.

Code Structure

  • Structure code like a newspaper article: most important logic first.
  • Keep functions focused and small; extract helpers when logic becomes hard to follow.
  • Group related functions, types, and interfaces together within a module.
  • Default file order (unless the file clearly uses another order):
    1. Imports
    2. Module-level constants and configuration
    3. Types and interfaces
    4. Implementation (functions, classes)
    5. Module exports

Formatting & Literals

  • Prefer single quotes for string literals.
  • Always end statements with semicolons.
  • Use template literals instead of string concatenation when interpolating values.
  • Avoid unused variables, parameters, and imports.

Naming

  • Use intention-revealing, descriptive names.
  • Types and interfaces: PascalCase.
    • If the project already uses prefixes like TExample or IExample, follow that pattern.
  • Variables and local constants: camelCase.
  • Classes and enums: PascalCase.
  • Booleans: prefix with is, has, can, or should (for example, isLoading, hasAccess, canRetry, shouldRetry).
  • File names: follow the existing convention; if none is obvious, use kebab-case for .ts and .tsx files.

Error Handling

  • Align with the project’s existing error-handling patterns.
  • New error types should:
    • Extend Error.
    • Set a meaningful name.
    • Optionally include a code field when useful.
  • Do not swallow errors silently; propagate or handle them consistently with nearby code.
  • When catching errors, narrow them using the style already used in the project (for example, instanceof, type guards, discriminated unions).

Logging & Tracing

  • Use the project’s existing logging or tracing mechanism.
  • When adding logs:
    • Include only relevant context (IDs, key parameters, high-level state).
    • Use clear, intention-revealing messages.
  • Avoid noisy logs in hot paths unless explicitly requested for diagnostics.

Types & Data Modeling

  • Prefer interfaces for object shapes that are extended or implemented.
  • Prefer type aliases for unions, intersections, utility types, and mapped types.
  • Use discriminated unions for variant states (for example, API results, state machines) when this matches existing patterns.
  • Prefer simple, explicit types over overly clever or deeply nested ones.
  • For external APIs (HTTP, events, messages), separate:
    • Raw transport types (for example, ApiUserResponse).
    • Internal domain types (for example, User).

Async Code & APIs

  • Prefer async/await over raw Promise chains unless the existing code uses a different style.
  • Always type async function return values explicitly (for example, Promise<User>).
  • For HTTP or IO boundaries:
    • Use existing typed clients or wrappers when available.
    • Centralize low-level HTTP or fetch logic instead of duplicating it across many modules.