이미지 로딩 중...
CodeDeck AI
2025. 11. 8. · 1 Views
TypeScript 에러 처리 패턴 완벽 가이드
TypeScript에서 안전하고 효율적인 에러 처리 방법을 배웁니다. try-catch부터 커스텀 에러, Result 패턴까지 실무에서 바로 사용할 수 있는 에러 처리 기법을 소개합니다.
들어가며
이 글에서는 TypeScript 에러 처리 패턴 완벽 가이드에 대해 상세히 알아보겠습니다. 총 10가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.
목차
- 기본_try_catch_패턴
- 타입_안전한_에러_처리
- 커스텀_에러_클래스
- Result_타입_패턴
- async_await_에러_처리
- 에러_경계_처리_유틸
- 에러_타입_좁히기
- Option_타입_패턴
- 에러_로깅_데코레이터
- 체이닝_가능한_Result
1. 기본_try_catch_패턴
개요
TypeScript에서 가장 기본적인 에러 처리 방법입니다. 예외가 발생할 수 있는 코드를 try 블록으로 감싸서 안전하게 처리합니다.
코드 예제
function parseJSON(jsonString: string): unknown {
try {
return JSON.parse(jsonString);
} catch (error) {
console.error('JSON 파싱 실패:', error);
return null;
}
}
설명
try 블록에서 JSON을 파싱하고, 실패 시 catch 블록에서 에러를 처리합니다. 에러 발생 시 null을 반환하여 프로그램이 중단되지 않습니다.
2. 타입_안전한_에러_처리
개요
TypeScript의 타입 가드를 사용하여 에러 객체의 타입을 안전하게 확인합니다. instanceof나 타입 체크로 에러의 종류를 구분할 수 있습니다.
코드 예제
try {
throw new Error('Something went wrong');
} catch (error) {
if (error instanceof Error) {
console.error(error.message);
} else {
console.error('알 수 없는 에러:', error);
}
}
설명
instanceof를 사용해 error가 Error 타입인지 확인합니다. 이를 통해 message 속성에 안전하게 접근할 수 있습니다.
3. 커스텀_에러_클래스
개요
에러의 종류를 명확히 구분하기 위해 Error 클래스를 상속받아 커스텀 에러를 만듭니다. 비즈니스 로직에 맞는 구체적인 에러를 정의할 수 있습니다.
코드 예제
class ValidationError extends Error {
constructor(public field: string, message: string) {
super(message);
this.name = 'ValidationError';
}
}
throw new ValidationError('email', '유효하지 않은 이메일');
설명
Error를 상속받아 ValidationError 클래스를 생성합니다. field 속성을 추가하여 어떤 필드에서 에러가 발생했는지 명확히 알 수 있습니다.
4. Result_타입_패턴
개요
에러를 예외로 던지지 않고 Result 타입으로 반환하는 함수형 패턴입니다. 성공과 실패를 명시적으로 처리할 수 있습니다.
코드 예제
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
function divide(a: number, b: number): Result<number, string> {
if (b === 0) return { ok: false, error: '0으로 나눌 수 없음' };
return { ok: true, value: a / b };
}
설명
Result 타입은 성공(ok: true)과 실패(ok: false)를 구분합니다. 에러를 예외가 아닌 값으로 다루어 더 예측 가능한 코드를 작성할 수 있습니다.
5. async_await_에러_처리
개요
비동기 함수에서 try-catch를 사용하여 Promise의 에러를 처리합니다. async/await와 함께 사용하면 동기 코드처럼 읽기 쉬운 에러 처리가 가능합니다.
코드 예제
async function fetchUser(id: string): Promise<User | null> {
try {
const response = await fetch(`/api/users/${id}`);
return await response.json();
} catch (error) {
console.error('사용자 조회 실패:', error);
return null;
}
}
설명
await 키워드를 사용한 비동기 작업을 try 블록으로 감쌉니다. 네트워크 에러나 JSON 파싱 에러가 발생하면 catch 블록에서 처리됩니다.
6. 에러_경계_처리_유틸
개요
여러 곳에서 반복되는 에러 처리 로직을 유틸 함수로 만들어 재사용합니다. 코드 중복을 줄이고 일관된 에러 처리를 보장합니다.
코드 예제
async function withErrorHandling<T>(
fn: () => Promise<T>,
fallback: T
): Promise<T> {
try {
return await fn();
} catch (error) {
console.error(error);
return fallback;
}
}
설명
제네릭 함수로 모든 타입의 비동기 작업에 에러 처리를 적용합니다. 에러 발생 시 fallback 값을 반환하여 안전하게 처리합니다.
7. 에러_타입_좁히기
개요
여러 종류의 커스텀 에러를 처리할 때 타입 가드로 에러 타입을 좁혀서 각각 다르게 처리합니다.
코드 예제
try {
// 작업 수행
} catch (error) {
if (error instanceof ValidationError) {
console.log(`필드 에러: ${error.field}`);
} else if (error instanceof NetworkError) {
console.log('네트워크 연결을 확인하세요');
}
}
설명
instanceof로 에러 타입을 구분하여 각 에러에 맞는 처리를 수행합니다. ValidationError는 필드 정보를, NetworkError는 재시도 로직을 실행할 수 있습니다.
8. Option_타입_패턴
개요
값이 없을 수 있는 상황을 타입으로 표현합니다. null/undefined 에러를 방지하고 안전하게 값의 존재 여부를 확인할 수 있습니다.
코드 예제
type Option<T> = T | null;
function findUser(id: string): Option<User> {
const user = users.find(u => u.id === id);
return user ?? null;
}
const user = findUser('123');
if (user !== null) console.log(user.name);
설명
Option 타입으로 값이 없을 수 있음을 명시합니다. null 체크를 강제하여 런타임 에러를 방지합니다.
9. 에러_로깅_데코레이터
개요
함수 실행 시 자동으로 에러를 로깅하는 데코레이터 패턴입니다. 에러 추적과 디버깅을 쉽게 만들어줍니다.
코드 예제
function catchErrors(target: any, key: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
descriptor.value = async function(...args: any[]) {
try {
return await original.apply(this, args);
} catch (error) {
console.error(`${key} 에러:`, error);
throw error;
}
};
}
설명
데코레이터로 함수를 감싸서 에러 발생 시 자동으로 로깅합니다. 함수 이름과 에러 정보를 함께 출력하여 디버깅을 용이하게 합니다.
10. 체이닝_가능한_Result
개요
Result 패턴을 확장하여 map, flatMap 등의 메서드로 에러 처리를 체이닝할 수 있습니다. 함수형 프로그래밍 스타일로 우아한 에러 처리가 가능합니다.
코드 예제
class Result<T, E> {
map<U>(fn: (value: T) => U): Result<U, E> {
return this.ok
? Result.success(fn(this.value))
: Result.failure(this.error);
}
static success<T>(value: T) { return new Result(true, value); }
}
설명
map 메서드로 성공 값을 변환하고, 실패 시 에러를 그대로 전파합니다. 여러 작업을 체이닝하면서 에러를 안전하게 처리할 수 있습니다.
마치며
이번 글에서는 TypeScript 에러 처리 패턴 완벽 가이드에 대해 알아보았습니다. 총 10가지 개념을 다루었으며, 각각의 사용법과 예제를 살펴보았습니다.
관련 태그
#TypeScript #ErrorHandling #TryCatch #CustomError #ResultPattern