/**
 * 취소 가능한 fetch 요청
 * @param url - 요청 URL
 * @param options - fetch 옵션
 * @returns {run, cancel} - run: 요청 실행 함수, cancel: 요청 취소 함수
 */
const createCancelableFetch = <T>(url: string, options: RequestInit = {}) => {
  const abortController = new AbortController()

  const run = async () => {
    const response = await fetch(url, {
      ...options,
      signal: abortController.signal,
    })

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }

    return response.json() as Promise<T>
  }

  const cancel = () => abortController.abort()

  return {
    run,
    cancel,
  }
}

const { run, cancel } = createCancelableFetch('/api/data')

run()
  .then((data) => console.log('Fetched data:', data))
  .catch((err) => console.error('Error or canceled:', err))

cancel()
#360