# Typescript Async Patterns

> When to activate: async/await, Promise patterns, concurrency, AbortController, error handling in async code, streams, async iterators

- Skill: `mattakushi432/typescript-async-patterns` (Agent Skill)
- Install (CLI): `npx skillmds@latest add mattakushi432/typescript-async-patterns`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mattakushi432/typescript-async-patterns/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Mattakushi432 (https://skillmd.com/u/mattakushi432)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/mattakushi432/typescript-async-patterns

---


# TypeScript Async Patterns

## Promise Combinators
```ts
// Parallel — all must succeed
const [user, posts, settings] = await Promise.all([
  fetchUser(id),
  fetchPosts(id),
  fetchSettings(id),
])

// Parallel — some may fail (inspects results individually)
const results = await Promise.allSettled([fetchA(), fetchB(), fetchC()])
results.forEach(r => {
  if (r.status === 'fulfilled') console.log(r.value)
  else console.error(r.reason)
})

// Race — first to resolve wins
const data = await Promise.race([fetchPrimary(), fetchFallback()])

// Any — first to succeed (ignores rejections unless all fail)
const fastest = await Promise.any([mirror1(), mirror2(), mirror3()])
```

## AbortController & Timeout
```ts
// Fetch with timeout
async function fetchWithTimeout<T>(url: string, ms = 5000): Promise<T> {
  const controller = new AbortController()
  const timer = setTimeout(() => controller.abort(), ms)
  try {
    const res = await fetch(url, { signal: controller.signal })
    if (!res.ok) throw new Error(`HTTP ${res.status}`)
    return res.json() as Promise<T>
  } finally {
    clearTimeout(timer)
  }
}

// Native timeout (Node 18+ / browsers)
const res = await fetch(url, { signal: AbortSignal.timeout(5000) })

// Cancel multiple operations
const controller = new AbortController()
const { signal } = controller

await Promise.all([
  fetch('/api/a', { signal }),
  fetch('/api/b', { signal }),
])

// Cancel all on user action
button.addEventListener('click', () => controller.abort())
```

## Async Retry with Backoff
```ts
async function withRetry<T>(
  fn: () => Promise<T>,
  { retries = 3, delay = 200, factor = 2 }: RetryOptions = {}
): Promise<T> {
  let lastError: unknown
  for (let attempt = 0; attempt <= retries; attempt++) {
    try {
      return await fn()
    } catch (err) {
      lastError = err
      if (attempt < retries) {
        await new Promise(r => setTimeout(r, delay * factor ** attempt))
      }
    }
  }
  throw lastError
}

const data = await withRetry(() => fetchUser(id), { retries: 3, delay: 500 })
```

## Async Queue / Rate Limiter
```ts
class AsyncQueue {
  private queue: Array<() => Promise<unknown>> = []
  private running = 0

  constructor(private concurrency: number) {}

  async add<T>(task: () => Promise<T>): Promise<T> {
    return new Promise((resolve, reject) => {
      this.queue.push(async () => {
        try { resolve(await task()) } catch (e) { reject(e) }
        finally { this.running--; this.next() }
      })
      this.next()
    })
  }

  private next() {
    while (this.running < this.concurrency && this.queue.length) {
      this.running++
      this.queue.shift()!()
    }
  }
}

// Usage: process up to 5 items in parallel
const queue = new AsyncQueue(5)
await Promise.all(items.map(item => queue.add(() => processItem(item))))
```

## Async Iterators & Generators
```ts
// Async generator — paginated API
async function* paginate<T>(
  fetcher: (cursor?: string) => Promise<{ items: T[]; next?: string }>
) {
  let cursor: string | undefined
  do {
    const { items, next } = await fetcher(cursor)
    yield* items
    cursor = next
  } while (cursor)
}

// Consume
for await (const user of paginate(cursor => api.users.list({ cursor }))) {
  await processUser(user)
}

// Readable stream as async iterator (Node 16+)
import { createReadStream } from 'node:fs'
const stream = createReadStream('large.csv', 'utf8')
for await (const chunk of stream) {
  process(chunk.toString())
}
```

## Deferred / Promise Handle
```ts
function createDeferred<T>() {
  let resolve!: (v: T) => void
  let reject!:  (e: unknown) => void
  const promise = new Promise<T>((res, rej) => { resolve = res; reject = rej })
  return { promise, resolve, reject }
}

// Usage: resolve from outside
const { promise, resolve } = createDeferred<string>()
setTimeout(() => resolve('done'), 1000)
const result = await promise
```

## Async Error Patterns
```ts
// Never lose errors in fire-and-forget
function fireAndForget(promise: Promise<unknown>) {
  promise.catch(err => console.error('Unhandled async error:', err))
}

// Result type to avoid try/catch everywhere
async function safe<T>(fn: () => Promise<T>): Promise<[T, null] | [null, Error]> {
  try {
    return [await fn(), null]
  } catch (e) {
    return [null, e instanceof Error ? e : new Error(String(e))]
  }
}

const [user, err] = await safe(() => fetchUser(id))
if (err) return handleError(err)
```

## Event Emitter → Promise
```ts
import { once } from 'node:events'

// Wait for a single event
const [data] = await once(emitter, 'data')

// With timeout
const timeout = AbortSignal.timeout(5000)
const [data] = await once(emitter, 'data', { signal: timeout })
```

