async saveUser(user: User) {
await dataSource.manager.save(someUser);
}
그리고 service계층에서 repository계층의 saveUser메소드를 가져다 사용하는 경우
saveUser메서드의 리턴타입은 새로운 타입을 정의한뒤 해당 타입을 리턴하는 것이 좋습니다
type NetworkErrorState = {
result: 'fail';
reason: 'offline' | 'down' | 'timeout';
};
type SuccessState = {
result: 'success';
};
type ResultState = SuccessState | NetworkErrorState; // Error State
async saveUser(user: User): ResultState {// Error State를 리턴
try {
await dataSource.manager.save(user)
return { result: 'success' } **// 성공한 상태 리턴**
} catch(err) {
return { result: 'fail', msg: '..' } **// 실패한 상태 리턴**
}
// 외부 or 상위 레벨에서 saveUser()를 사용하는 부분에는
// try catch를 사용 할 필요가 없다
// 그냥 ResultState만 리턴받아서 if문을 통해 로직을 진행
로직을 실행할 때 그 결과는 3가지로 분류가 됩니다
예상하는
실패적인 케이스 (예: 사용자가 잘못된 비밀번호를 입력해서 로그인 실패 )예상하지 않는
, 대게 일어 나지 않는 케이스의 에러. 어플리케이션에서 예상하지 않는, 예외적으로 발생하는 에러 (예: 네트워크 오류, 메모리 부족, 서버 다운 등)어플리케이션에서 예상할 수 있는 Expected Errors에 대해서는 가급적 exception (throw error) 에러를 던지기 보다는, 에러 상태를 나타낼 수 있는 타입을 사용하는것이 좋습니다
async function saveUser(user: User)
여기서 실패했을때 갑작스럽게, 예외적으로 에러 throw해서 ,
service 레벨에서 사용하는 사람이 알아서 try-catch를 사용하게 만드는것 보다는
async function saveUser(user: User)
: SuccessState | NetworkErrorState
이렇게 성공할수 있고, 실패할 수 있다는 설명을 해주는게 좋습니다
ResultState와 같은 에러의 상태
는 saveUser 같은 서비스를 사용하는
어플리케이션 service레벨에서 나의 서비스를 사용하는 대상이
적절하게 대응을 하고자 하는 에러들을 알 수 있도록, `어떤 에러 상태
인지 알 수 있게` 사용자 입맛에 맞게 만들어 주는게 좋습니다
async saveUser(user: User): User | undefined
단순히 성공했는지, 실패했는지만 궁금하다면, 별도의 ResultState 타입
을 만들 필요 없이, 성공했다면 저장된 user를 반환하고 그렇지 않다면
undefined을 반환하는것으로 함수의 인터페이스를 만들어도 됩니다
여기서 왜 저장하지 못했는지 이유를 알고 싶다면 위처럼 ResultState 같은 타입을 도입하면 되는 것입니다
무조건적으로 throw를 지양하자! (X)
예상하지 못한 Exceptional Errors에만 throw를 사용하자! (O)
Expected Errors에서는 무조건 State를 사용하자! (X)
사용하는자의 관심도와 필요에 따라서, State를 사용하면 된다 (O)
( 위처럼 단순히 성공했는지, 실패했는지만 궁금하다면
User | undefined를 리턴해도 됨 )