Smithery Logo
MCPsSkillsDocsPricing
Login
NewFlame, an assistant that learns and improves. Available onTelegramSlack
    JasonDocton

    typescript-patterns

    JasonDocton/typescript-patterns
    Coding
    2

    About

    SKILL.md

    Install

    • Telegram
      Telegram
    • Slack
      Slack
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    • Download skill
    ├─
    ├─
    └─
    Smithery Logo

    Give agents more agency

    Resources

    DocumentationPrivacy PolicySystem Status

    Company

    PricingAboutBlog

    Connect

    © 2026 Smithery. All rights reserved.

    About

    TypeScript style and type safety patterns. Applies to TSX, TS code, interfaces, types, generics, unions, type errors.

    SKILL.md

    TypeScript Patterns

    Rules (always apply)

    Pattern Do Don't
    Object shapes interface type
    Composition interface extends type &
    Unions discriminated, <10 members bag of optionals
    Constants as const objects enum
    Imports import type { T } import { type T }
    Return types explicit on exports infer (except JSX)
    Validation satisfies manual annotation
    Data readonly default mutable default
    Mutation spread operator direct mutation
    Async Promise.all when independent sequential awaits

    Before Creating Any Type

    1. Does it exist in schema/API?
    2. Can I derive it?
    3. Am I the source of truth?

    For Convex: see convex-patterns/SKILL.md.

    Discriminated Unions

    // ✅
    type AsyncState<T> =
      | { status: "idle" }
      | { status: "loading" }
      | { status: "success"; data: T }
      | { status: "error"; error: Error }
    
    // ❌ allows impossible states
    type AsyncState<T> = { status: string; data?: T; error?: Error }
    

    satisfies for Validation

    // ✅ validates + infers literal types
    return { type, severity, description } satisfies Partial<FraudFlag>
    
    // ❌ loses inference
    function createConfig(): Partial<Config> { return { timeout: 5000 } }
    

    Explicit undefined vs Optional

    // ✅ forces acknowledgment
    interface CreateUser { referrerId: string | undefined }
    
    // ❌ silent omission possible
    interface CreateUser { referrerId?: string }
    

    interface extends > type &

    // ✅ cached, flat
    interface ButtonProps extends BaseProps, InteractiveProps {
      variant: "primary" | "secondary"
    }
    
    // ❌ recursive merge, slow
    type ButtonProps = BaseProps & InteractiveProps & { variant: "primary" | "secondary" }
    

    Use & only for: type A = (B | C) & D

    as const > enum

    // ✅ tree-shakeable, no runtime
    const Status = { Pending: "pending", Active: "active" } as const
    type Status = (typeof Status)[keyof typeof Status]
    
    // ❌ generates runtime code
    enum Status { Pending = "pending" }
    

    Immutability

    // ✅ spread
    const updated = { ...user, name: "New" }
    const added = [...items, newItem]
    
    // ❌ mutation
    user.name = "New"
    items.push(newItem)
    

    Parallel Async

    // ✅ parallel
    const [users, markets] = await Promise.all([fetchUsers(), fetchMarkets()])
    
    // ❌ sequential (when independent)
    const users = await fetchUsers()
    const markets = await fetchMarkets()
    

    Large Unions (>10 members)

    // ❌ O(n²)
    type Status = "pending" | "processing" | "confirmed" | "shipped" | ...
    
    // ✅ nested
    type Status =
      | { category: "active"; state: "pending" | "processing" }
      | { category: "completed"; state: "delivered" | "shipped" }
    

    Exhaustiveness Checking

    switch (state.status) {
      case "success": return ...
      default: {
        const _exhaustive: never = state
        throw new Error("Unhandled state")
      }
    }
    

    Extract Complex Conditionals

    // ❌ recalculated
    interface Api<T> { fetch<U>(x: U): U extends TypeA<T> ? ProcessA<U, T> : U }
    
    // ✅ cached
    type FetchResult<U, T> = U extends TypeA<T> ? ProcessA<U, T> : U
    interface Api<T> { fetch<U>(x: U): FetchResult<U, T> }
    

    When type is Correct

    • Unions: type Result = Success | Error
    • Mapped types: type Readonly<T> = { readonly [K in keyof T]: T[K] }
    • Conditionals: type Unwrap<T> = T extends Promise<infer U> ? U : T
    • Tuples: type Pair = [string, number]
    • Schema derivation: type User = Infer<typeof userValidator>
    • Generic constraints needing index signatures
    Recommended Servers
    URL Safety Validator MCP
    URL Safety Validator MCP
    Hugeicons MCP Server
    Hugeicons MCP Server
    OpenZeppelin
    OpenZeppelin
    Repository
    jasondocton/rad-claude
    Files