SHIN STORYSHIN STORY
홈포스트C#TypeScriptNext.jsNode.js시리즈
</>SHIN STORY

sdf

탐색

  • 홈
  • 모든 포스트
  • 시리즈
  • 검색

카테고리

  • C#
  • TypeScript
  • Next.js
  • Node.js
  • 알고리즘
  • 개발 도구

© 2025 Shin Blog. All rights reserved.

GitHubRSS
목록으로
TypeScript#TypeScript

TypeScript 팁 #9 — 타입 안전한 에러 처리 패턴

SHIN

2025년 5월 1일2분 읽기0
📚

TypeScript 실전 팁 10선

10편
  1. 5TypeScript 팁 #5 — 타입 가드로 런타임 타입 좁히기
  2. 6TypeScript 팁 #6 — 매핑 타입으로 타입 변환하기
  3. 10TypeScript 팁 #1 — strict 모드를 반드시 켜야 하는 이유
  4. 10TypeScript 팁 #2 — 유틸리티 타입 완전 정복
  5. 10TypeScript 팁 #3 — 판별 유니온으로 타입 안전한 상태 관리
  6. 10TypeScript 팁 #4 — 제네릭 제약 조건과 infer 활용
  7. 10TypeScript 팁 #7 — 템플릿 리터럴 타입으로 문자열 타입 조작
  8. 10TypeScript 팁 #8 — 선언 병합과 모듈 보강으로 타입 확장하기
  9. TypeScript 팁 #9 — 타입 안전한 에러 처리 패턴현재
  10. 10TypeScript 팁 #10 — 타입 성능 최적화와 실무 패턴

TypeScript 팁 #9 — 타입 안전한 에러 처리 패턴

catch의 unknown 타입

TypeScript 4.0부터 catch 변수의 기본 타입이 any 대신 unknown으로 변경되었습니다(useUnknownInCatchVariables).

CODE
// ❌ any를 그냥 사용 — 타입 안전하지 않음
try {
  await fetchData()
} catch (err: any) {
  console.log(err.message)  // 런타임에 undefined일 수 있음
}

// ✅ unknown을 instanceof로 처리
try {
  await fetchData()
} catch (err) {
  if (err instanceof Error) {
    console.log(err.message)  // ✅ Error로 좁혀짐
  } else if (typeof err === 'string') {
    console.log(err)
  } else {
    console.log('알 수 없는 오류:', err)
  }
}

에러 타입 계층 구조

CODE
class AppError extends Error {
  constructor(
    message: string,
    public readonly code: string,
    public readonly statusCode = 500
  ) {
    super(message)
    this.name = this.constructor.name
  }
}

class ValidationError extends AppError {
  constructor(message: string, public readonly field: string) {
    super(message, 'VALIDATION_ERROR', 400)
  }
}

class NotFoundError extends AppError {
  constructor(resource: string) {
    super(`${resource}을(를) 찾을 수 없습니다`, 'NOT_FOUND', 404)
  }
}

// 에러 처리
function handleError(err: unknown): Response {
  if (err instanceof ValidationError) {
    return Response.json({ field: err.field, message: err.message }, { status: 400 })
  }
  if (err instanceof NotFoundError) {
    return Response.json({ message: err.message }, { status: 404 })
  }
  if (err instanceof AppError) {
    return Response.json({ message: err.message }, { status: err.statusCode })
  }
  return Response.json({ message: '서버 오류' }, { status: 500 })
}

Result 패턴 — 예외 없이 에러 표현

함수가 에러를 던지는 대신 반환값으로 에러를 표현합니다.

CODE
type Result<T, E = Error> =
  | { ok: true;  value: T }
  | { ok: false; error: E }

function ok<T>(value: T): Result<T> {
  return { ok: true, value }
}

function err<E = Error>(error: E): Result<never, E> {
  return { ok: false, error }
}

// 사용
async function parseJson(text: string): Promise<Result<unknown>> {
  try {
    return ok(JSON.parse(text))
  } catch (e) {
    return err(e instanceof Error ? e : new Error(String(e)))
  }
}

const result = await parseJson('{ invalid }')
if (result.ok) {
  console.log(result.value)  // ✅ 성공
} else {
  console.error(result.error.message)  // ✅ 에러
}

에러 정보 안전하게 추출

CODE
function getErrorMessage(err: unknown): string {
  if (err instanceof Error) return err.message
  if (typeof err === 'string') return err
  if (typeof err === 'object' && err !== null && 'message' in err) {
    return String((err as { message: unknown }).message)
  }
  return '알 수 없는 오류가 발생했습니다'
}

// 활용
try {
  await riskyOperation()
} catch (err) {
  toast.error(getErrorMessage(err))  // 항상 string 반환
}

비동기 에러를 타입으로 표현 — try-catch 최소화

CODE
// Promise를 Result로 래핑
async function tryCatch<T>(
  promise: Promise<T>
): Promise<Result<T>> {
  try {
    return ok(await promise)
  } catch (e) {
    return err(e instanceof Error ? e : new Error(String(e)))
  }
}

// 사용 — try/catch 없이 깔끔하게
const { ok: success, value, error } = await tryCatch(fetchUser(1))

if (!success) {
  console.error(error.message)
  return
}

// 여기서 value는 User
console.log(value.name)

에러 처리를 타입 시스템에 녹이면 "이 함수가 어떤 에러를 낼 수 있는가"가 시그니처에서 명확하게 드러나 유지보수성이 높아집니다.

공유
S

SHIN

.NET 개발자입니다

GitHub
TypeScript 팁 #8 — 선언 병합과 모듈 보강으로 타입 확장하기

이전 포스트

TypeScript 팁 #8 — 선언 병합과 모듈 보강으로 타입 확장하기

다음 포스트

TypeScript 팁 #10 — 타입 성능 최적화와 실무 패턴

TypeScript 팁 #10 — 타입 성능 최적화와 실무 패턴

같은 카테고리 포스트

TypeScript 팁 #10 — 타입 성능 최적화와 실무 패턴

TypeScript 팁 #10 — 타입 성능 최적화와 실무 패턴

2025년 5월 3일· 3분
TypeScript 팁 #8 — 선언 병합과 모듈 보강으로 타입 확장하기

TypeScript 팁 #8 — 선언 병합과 모듈 보강으로 타입 확장하기

2025년 4월 29일· 2분
TypeScript 팁 #7 — 템플릿 리터럴 타입으로 문자열 타입 조작

TypeScript 팁 #7 — 템플릿 리터럴 타입으로 문자열 타입 조작

2025년 4월 27일· 2분

댓글