I recently created a Result monad that is nearly functioning :)
class Result<T> {
private readonly value: T;
private readonly error: Error;
constructor(value?: T, error?: Error) {
if (value) {
this.value = value;
}
if (error) {
this.error = error;
}
}
static ok<T>(ok: T): Result<T> {
return new Result<T>(ok);
}
static error<T>(err: Error): Result<T> {
return new Result<T>(undefined, err);
}
isOk(): boolean {
return this.value !== undefined;
}
isError(): boolean {
return this.error !== undefined;
}
chain<U>(f: (t: T) => Result<U>): Result<U> {
return this.isOk() ?
f(this.value) :
Result.error<U>(this.error);
}
map<U>(f: (t: T) => U): Result<U> {
return this.isOk() ?
Result.ok<U>(f(this.value)) :
Result.error<U>(this.error);
}
concat<U>(aResult: Result<U>): Result<(T | U)[]> {
return this.isOk() ?
Result.ok<(T | U)[]>(Array().concat(this.value, aResult.getValue())) :
Result.error(this.error);
}
getError(): Error {
return this.error;
}
getValue(): T {
return this.value;
}
}
Instructions for using it:
const r1 = Result.ok(76)
.concat(Result.ok('ddd'))
.concat(Result.ok(true))
.map((i: (number | string | boolean)[]) => i);
In this case, I am combining three results: an integer, a string, and a boolean.
Following that, I plan to apply a transformation method on them by mapping.
The .map function requires the input as (number | string | boolean)[].
Unfortunately, an error message pops up:https://i.sstatic.net/IbztE.png
Although I understand the issue, I'm unsure about the solution.
The problem lies within the .concat function:
concat<U>(aResult: Result<U>): Result<(T | U)[]> {
return this.isOk() ?
Result.ok<(T | U)[]>(Array().concat(this.value, aResult.getValue())) :
Result.error(this.error);
}
Whenever there's concatenation, this method is called repeatedly—a form of recursion.
This is how it occurs in my scenario:
first concatenation - U represents the string 'ddd', and T stands for the number 76. This returns a (number | string)[]
second concatenation - U is already a (number | string)[] and now accepts a boolean. Instead of returning (number | string | boolean)[], TypeScript yields (boolean | (number | string)[])[]
Is there a way to modify the concat function to accept the signature (string | number | boolean)[]?
Any suggestions or solutions would be appreciated.