Created
January 3, 2025 14:38
-
-
Save ravicious/e3764f4647c38f58d3afddbb40ba3311 to your computer and use it in GitHub Desktop.
useAsync: andMap, map2, map3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
describe('andMap', () => { | |
const tests: Array<{ | |
statusA: AttemptStatus; | |
statusB: AttemptStatus; | |
expectedStatus: AttemptStatus; | |
}> = [ | |
{ | |
statusA: 'success', | |
statusB: 'success', | |
expectedStatus: 'success', | |
}, | |
{ | |
statusA: 'success', | |
statusB: 'error', | |
expectedStatus: 'error', | |
}, | |
{ | |
statusA: 'success', | |
statusB: 'processing', | |
expectedStatus: 'processing', | |
}, | |
{ | |
statusA: 'success', | |
statusB: '', | |
expectedStatus: '', | |
}, | |
{ | |
statusA: 'error', | |
statusB: 'success', | |
expectedStatus: 'error', | |
}, | |
{ | |
statusA: 'processing', | |
statusB: 'success', | |
expectedStatus: 'processing', | |
}, | |
{ | |
statusA: '', | |
statusB: 'success', | |
expectedStatus: '', | |
}, | |
{ | |
statusA: 'processing', | |
statusB: 'error', | |
expectedStatus: 'error', | |
}, | |
{ | |
statusA: '', | |
statusB: 'processing', | |
expectedStatus: 'processing', | |
}, | |
]; | |
test.each(tests)( | |
'andMap("$statusA", "$statusB") = "$expectedStatus"', | |
({ statusA, statusB, expectedStatus }) => { | |
const attemptA = makeAttemptFromStatus('foo', statusA); | |
const attemptB = makeAttemptFromStatus((a: string) => a, statusB); | |
expect(andMap(attemptA, attemptB).status).toEqual(expectedStatus); | |
} | |
); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* andMap together with mapAttempt and currying allow mapping an arbitrary number of attempts in a | |
* type-safe way. Prefer using map2 and map3 where possible. | |
*/ | |
export function andMap<A, B>( | |
wrappedValue: Attempt<A>, | |
wrappedFunction: Attempt<(dataA: A) => B> | |
): Attempt<B> { | |
if ( | |
wrappedFunction.status === 'success' && | |
wrappedValue.status === 'success' | |
) { | |
const func = wrappedFunction.data; | |
const value = wrappedValue.data; | |
return makeSuccessAttempt(func(value)); | |
} | |
if (wrappedFunction.status === 'error') { | |
return wrappedFunction; | |
} | |
if (wrappedValue.status === 'error') { | |
return wrappedValue; | |
} | |
if (wrappedFunction.status === 'processing') { | |
return makeProcessingAttempt(); | |
} | |
if (wrappedValue.status === 'processing') { | |
return makeProcessingAttempt(); | |
} | |
if (wrappedFunction.status === '') { | |
return wrappedFunction; | |
} | |
if (wrappedValue.status === '') { | |
return wrappedValue; | |
} | |
} | |
/** | |
* map2 combines two attempts. The resulting attempt will be successful only if both attempts are | |
* successful. Otherwise the result will be the first encountered error, processing, or empty | |
* attempt, in that order. | |
*/ | |
export function map2<A, B, C>( | |
attemptA: Attempt<A>, | |
attemptB: Attempt<B>, | |
mapFunc: (dataA: A, dataB: B) => C | |
): Attempt<C> { | |
const curriedMapFunc = (dataA: A) => (dataB: B) => mapFunc(dataA, dataB); | |
return andMap(attemptB, mapAttempt(attemptA, curriedMapFunc)); | |
} | |
/** | |
* map3 combines three attempts. The resulting attempt will be successful only if all attempts are | |
* successful. Otherwise the result will be the first encountered error, processing, or empty | |
* attempt, in that order. | |
*/ | |
export function map3<A, B, C, D>( | |
attemptA: Attempt<A>, | |
attemptB: Attempt<B>, | |
attemptC: Attempt<C>, | |
mapFunc: (dataA: A, dataB: B, dataC: C) => D | |
): Attempt<D> { | |
const curriedMapFunc = (dataA: A) => (dataB: B) => (dataC: C) => | |
mapFunc(dataA, dataB, dataC); | |
return andMap( | |
attemptC, | |
andMap(attemptB, mapAttempt(attemptA, curriedMapFunc)) | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment