Either
Handling Exceptions With Either "Left" Or "Right"
either.ts
ts
export class Left<T> {
readonly error: T;
private constructor(error: T) {
this.error = error;
}
isLeft(): this is Left<T> {
return true;
}
isRight(): this is Right<never> {
return false;
}
static create<U>(error: U): Left<U> {
return new Left(error);
}
}
export class Right<T> {
readonly value: T;
private constructor(value: T) {
this.value = value;
}
isLeft(): this is Left<never> {
return false;
}
isRight(): this is Right<T> {
return true;
}
static create<U>(value: U): Right<U> {
return new Right(value);
}
}
export type Either<T, U> = Left<T> | Right<U>;
either.test.ts
ts
type JsonPrimitive = string | number | boolean | null | undefined;
type JsonObject = { [key: string]: JsonValue };
type JsonValue = JsonPrimitive | JsonValue[] | JsonObject;
const evaluate = (value: JsonValue): Either<Error, JsonValue> => {
if (typeof value === "object" && value !== null) {
if (Array.isArray(value) && value.length === 0) {
return Left.create(new Error("Empty Array"));
}
if (Object.values(value).length === 0) {
return Left.create(new Error("Empty Object"));
}
}
if (!value) return Left.create(new Error("Value Is Falsy"));
return Right.create(value);
};
test("it should returns left error", () => {
const result = evaluate({});
const error = new Error("Empty Object");
expect(result.isLeft()).toBe(true);
expect((result as Left<Error>).error).toEqual(error);
});
test("it should returns right value", () => {
const obj = { message: "Hi!" };
const result = evaluate(obj);
expect(result.isRight()).toBe(true);
expect((result as Right<JsonValue>).value).toEqual(obj);
});