기존 async/await
을 쓸경우 다음과 같이 쓸 수 있다.
export async function isOddNum(num: number): Promise<boolean> {
if (typeof num !== "number") throw Error('Invalid parameter type')
if (num < 1) throw Error('Must be number >= 1')
return num % 2 === 1
}
describe('Origin Promise Odd', ()=>{
test('Success with one', async ()=>{
const isOdd = await isOddNum(3)
expect(isOdd).toBeTruthy()
})
test('Fail with zero', async ()=>{
const isOdd = await isOddNum(0)
// ⚠️ Error occurs since it can't receive error from 'throw'
expect(isOdd).toBeFalsy()
})
})
아쉽지만 아래 케이스에서 에러가 발생한다.
이는 Promise 에서 reject()
하거나 async 함수에서 throw()
할 때 다음과 같이 같이 에러를 핸들링 해줘야하기 때문이다.
reject()
-> .catch()
throw
-> try ~ catch()
위 코드를 정상작동 시키기 위해 다음과 같이 개선할 수 있다.
test('Fail with zero', async ()=>{
const isOdd = await isOddNum(0)
try {
expect(isOdd).toBeFalsy()
// ✅ catch 로 Error handling
} catch (e) {
console.error(e)
}
})
문제가 해결된 것 같은가?
그럼 우린 항상 async/await 을 쓸 때마다try ~ catch
를 받아야하나?
async/await - try catch 코드는 안전하긴 하지만 코드가 간결하다고 보긴 어렵다. 이런 해결하기 위해 neverhrow 에서 해법을 제시한다.
우선 neverthrow 를 설치하라
$ yarn add neverthrow
export function isOddNumWithNeverThrow(num: number): ResultAsync<boolean, Error> {
if (typeof num !== "number") return errAsync(new Error('Invalid parameter type'))
if (num < 1) return errAsync(new Error('Must be number >= 1'))
return okAsync(num % 2 === 1)
}
describe('isOddCheck with fromPromise',()=>{
test('Success with one',async ()=>{
const result = await isOddNumWithNeverThrow(1)
expect(result.isOk()).toBeTruthy()
expect(result.isErr()).toBeFalsy()
})
test('Fail with zero', async ()=>{
const result = await isOddNumWithNeverThrow(0)
expect(result.isOk()).toBeFalsy()
expect(result.isErr()).toBeTruthy()
})
})
try ~ catch 구문이 사라지고
isOk()
,isErr()
메소드로 indent 없이 위에서 아래로 읽히는 코드로 개선됐다.
declare class ResultAsync<T, E> implements PromiseLike<Result<T, E>> {
// ..
static fromSafePromise<T, E = never>(promise: PromiseLike<T>): ResultAsync<T, E>;
static fromPromise<T, E>(promise: PromiseLike<T>, errorFn: (e: unknown) => E): ResultAsync<T, E>;
// ..
}
리턴 타입이 ResultAsync<T,E>
다.
옛날 Javascript 스팩에는 Promise API 가 공식적으로 존재하지 않고, 콜백을 통해 비동기를 처리했었다.
Promise API 를 제공하기 위한 서드파티 라이브러리가 있었는데 대표적인 예가 다음 2개다.
PromiseLike 과 Promise 의 차이점은 .catch 의 유무다. PromiseLike 은 오로지 .then() 으로만 결과를 처리했었다.
async/await - try/catch 코드에서 neverthrow 에서 제공하는 API 로 가독성 높은 코드를 작성하는 것을 고려해보자.
더 자세한 설명을 원한다면 이 neverthrow - wiki 를 참고하자.