Either 타입

계산의 실패나 오류를 던지는 부분 함수를 다루기 위해 어떻게 Option 자료형을 활용하는지 살펴보았습니다.

하미잔 이 자료형은 어떤 상황에서는 제한적일 수 있습니다. 성공하는 경우 A 의 정보를 포함한 Some<A> 을 얻지만 None 은 어떠한 데이터도 가지고 있지 않습니다. 즉 실패했다는 것은 알지만 그 이유를 알 수 없습니다.

이를 해결하기 위해 실패를 표현하는 새로운 자료형이 필요하며 이를 Left<E> 로 부르겠습니다. 또한 Some<A>Right<A> 로 변경됩니다.

// 실패를 표현 interface Left<E> { readonly _tag: 'Left' readonly left: E } // 성공을 표현 interface Right<A> { readonly _tag: 'Right' readonly right: A } type Either<E, A> = Left<E> | Right<A>

생성자와 패턴 매칭은 다음과 같습니다:

const left = <E, A>(left: E): Either<E, A> => ({ _tag: 'Left', left }) const right = <A, E>(right: A): Either<E, A> => ({ _tag: 'Right', right }) const match = <E, R, A>(onLeft: (left: E) => R, onRight: (right: A) => R) => ( fa: Either<E, A> ): R => { switch (fa._tag) { case 'Left': return onLeft(fa.left) case 'Right': return onRight(fa.right) } }

이전 callback 예제로 돌아가봅시다:

declare function readFile( path: string, callback: (err?: Error, data?: string) => void ): void readFile('./myfile', (err, data) => { let message: string if (err !== undefined) { message = `Error: ${err.message}` } else if (data !== undefined) { message = `Data: ${data.trim()}` } else { // should never happen message = 'The impossible happened' } console.log(message) })

이제 다음과 같이 signature 를 변경할 수 있습니다:

declare function readFile( path: string, callback: (result: Either<Error, string>) => void ): void

그리고 다음과 같이 사용합니다:

readFile('./myfile', (e) => pipe( e, match( (err) => `Error: ${err.message}`, (data) => `Data: ${data.trim()}` ), console.log ) )