Consider this intricate collection of functions:
interface Succes<a> {
kind: 'succes'
value: a
}
interface Failure<e> {
kind: 'failure'
error: e
}
type Result<a, e> = Succes<a> | Failure<e>
const unit = <a>(a:a): Succes<a> => ({kind: 'succes', value: a})
const fail = <e>(e:e): Failure<e> => ({kind: 'failure', error: e})
interface fun<a, b> { (a: a): b }
const map = <a,b, e>(f: fun<a, b>): fun<Result<a,e>, Result<b,e>> => r =>
r.kind == 'succes' ? unit(f(r.value)) : r
const join = <a, e>(r:Result<Result<a, e>, e>): Result<a, e> =>
r.kind == 'failure' ? r : r.value
const then = <a, b, e>(f:fun<a, Result<b, e>>) => (r:Result<a, e>) =>
join(map(f)(r))
const railSystem = <a, e>(r: Result<a, e>) => ({
map: <b>(f: (a:a) => b) => railRoad<b, e>(map<a, b, e>(f)(r)),
then: <b>(f: (a:a) => Result<b,e>) => railSystem(then(f)(r))
})
Focus on the railSystem
section, which allows us to structure our code like this:
railSystem<User, *possibleErrors*>(getUser())
.then(formatName)
.map(greet)
This approach is promising as it handles errors throughout multiple function calls, but we must define the potential errors in advance. Could we dynamically determine the error types based on subsequent .then
or .map
functions?
Is it possible for the e
in railSystem
to adjust according to the signature of chained functions passed through .then
or .map
? This would allow the original railSystem
function to infer the error type.
An interactive TypeScript demonstration can be accessed here