type FetchWithAbortResult =
  | { response: Response; abort: () => void }
  | { error: NetworkError | HttpError }

class NetworkError extends Error {
  constructor(message: string) {
    super(message)
    this.name = 'NetworkError'
  }
}

class HttpError extends Error {
  constructor(public status: number, message?: string) {
    super(message || `HTTP error: ${status}`)
    this.name = 'HttpError'
  }
}

async function fetchWithAbortController(
  url: string,
  options: RequestInit = {}
): Promise<FetchWithAbortResult> {
  const controller = new AbortController()
  const { signal } = controller

  try {
    const response = await fetch(url, { ...options, signal })

    if (!response.ok) {
      throw new HttpError(response.status)
    }

    return {
      response,
      abort: () => controller.abort(),
    }
  } catch (error) {
    if (error.name === 'AbortError') {
      return {
        error: new NetworkError(),
      }
    }

    const e =
      error instanceof HttpError ? error : new NetworkError(error.message)

    return {
      error: e,
    }
  }
}
  • API 요청 시 발생할 수 있는 오류 문제의 필요성
  • AbortController 사용과 사용자 정의 에러 클래스를 통한 에러 관리
  • HTTP 요청과 네트워크 오류를 안정적으로 처리
#378