Modeling a Value with Possible Errors in TypeScript
I'm curious how best to model this, i.e. if there are any built-in types to model "a value, with maybe some errors"
I have a cache of all the data my frontend has loaded:
type MyData = // some type of datatype MyError = // network error, or parsing error, or whatever. some discriminated union type// I want to model something like "the last value fetched was A and maybe it's stale that's ok. The last fetch optionally had some errors// So any use case can always rely on showing the user *some value*, and can optionally choose to care about the errors (including to figure out whether the value is stale)type ValueAndMaybeError<A, E> = // ??cache: Record<string, ValueAndMaybeError<MyData, MyError>>
type MyData = // some type of datatype MyError = // network error, or parsing error, or whatever. some discriminated union type// I want to model something like "the last value fetched was A and maybe it's stale that's ok. The last fetch optionally had some errors// So any use case can always rely on showing the user *some value*, and can optionally choose to care about the errors (including to figure out whether the value is stale)type ValueAndMaybeError<A, E> = // ??cache: Record<string, ValueAndMaybeError<MyData, MyError>>
In particular, I want to model this so it's easy to "merge in" the results of the next fetch:
// functions to fetch one, or many, or whateverdeclare const fetchOne: (...) => Effect<MyData, MyError, never>declare const fetchMany: (...) => Effect<Record<string, MyData>, MyError, never>;// run any fetch call to get the Either result of the callconst result = yield* Effect.either(fetchOneOrMany());// Now I want this part to be easyconst updateValue = ( existing: ValueAndMaybeError<MyData, MyError>, result: Either<MyData, MyError>) : ValueAndMaybeError<MyData, MyError> => { // if result is success, return ValueAndMaybeError with MyData and clear the error // if result is failure, return ValueAndMaybeError with the existing value, and replace any error from before with the one from result}
// functions to fetch one, or many, or whateverdeclare const fetchOne: (...) => Effect<MyData, MyError, never>declare const fetchMany: (...) => Effect<Record<string, MyData>, MyError, never>;// run any fetch call to get the Either result of the callconst result = yield* Effect.either(fetchOneOrMany());// Now I want this part to be easyconst updateValue = ( existing: ValueAndMaybeError<MyData, MyError>, result: Either<MyData, MyError>) : ValueAndMaybeError<MyData, MyError> => { // if result is success, return ValueAndMaybeError with MyData and clear the error // if result is failure, return ValueAndMaybeError with the existing value, and replace any error from before with the one from result}
I could probably force it with a Tuple or discriminated union or just simply
{ value: A, error: Option<E> }
{ value: A, error: Option<E> }
, and just implement all this pseudocode... but I suspect that the correct choice of types will simplify this a lot