Skip to content

Instantly share code, notes, and snippets.

@ThinaticSystem
Last active May 16, 2026 05:49
Show Gist options
  • Select an option

  • Save ThinaticSystem/052e986b8d8f90f19219283d48e469e2 to your computer and use it in GitHub Desktop.

Select an option

Save ThinaticSystem/052e986b8d8f90f19219283d48e469e2 to your computer and use it in GitHub Desktop.
result.js
// @ts-check
"use strict";
/**
* @template TSuccessValue
* @template {'success' | 'error'} [TStatus='success' | 'error']
*/
export class Result {
/**
* @readonly
* @type {TStatus}
*/
status;
/**
* @readonly
* @type {TStatus extends "success" ? TSuccessValue : unknown}
*/
value;
/**
* @template TSuccessValue
* @param {TSuccessValue} value
*/
static success = (value) => new Result("success", value);
/**
* @param {unknown} value
*/
static error = (value) => /** @type {Result<never, "error">} */ (new Result("error", value));
/**
* @template TResult
* @param {() => Promise<TResult>} process
* @returns {Promise<Result<TResult>>}
*/
static wrapAsyncProcess = async (process) => {
try {
const data = await process();
return new Result("success", data);
} catch (error) {
return /** @type {Result<TResult, "error">} */ (new Result("error", error));
}
};
/**
* @param {TStatus} status
* @param {TStatus extends "success" ? TSuccessValue : unknown} value
*/
constructor(status, value) {
this.status = status;
this.value = value;
}
/**
* @template [TSuccessMapped=TSuccessValue]
* @param {{
* success?: (value: TSuccessValue) => TSuccessMapped,
* error?: (value: unknown) => unknown,
* }} handlers
* @returns {Result<TSuccessMapped>}
*/
map(handlers) {
try {
switch (this.status) {
case "success": {
const mappedValue = handlers.success
? handlers.success(/** @type {TSuccessValue} */ (this.value))
: /** @type {TSuccessMapped} */ (this.value);
return Result.success(mappedValue);
}
case "error": {
const mappedError = handlers.error
? handlers.error(/** @type {unknown} */ (this.value))
: this.value;
return Result.error(mappedError);
}
}
} catch (mappingError) {
console.error("Error occurred while mapping Result:", mappingError);
return Result.error(mappingError);
}
}
unwrapOrThrow() {
switch (this.status) {
case "success":
return /** @type {TSuccessValue} */ (this.value);
case "error":
console.error("Error occurred while unwrapping Result:", this.value);
throw this.value;
}
}
/**
* @template TDefaultValue
* @param {TDefaultValue} defaultValue
*/
unwrapOr(defaultValue) {
switch (this.status) {
case "success":
return /** @type {TSuccessValue} */ (this.value);
case "error":
return defaultValue;
}
}
}
export class Result<TSuccessValue, TStatus extends "success" | "error" = "success" | "error"> {
readonly status: TStatus;
readonly value: TStatus extends "success" ? TSuccessValue : unknown;
static success = <TSuccessValue>(value: TSuccessValue) => new Result("success", value);
static error = (value: unknown) => new Result("error", value) as Result<never, "error">;
static wrapAsyncProcess = async <TResult>(
process: () => Promise<TResult>,
): Promise<Result<TResult>> => {
try {
const data = await process();
return new Result("success", data);
} catch (error) {
return new Result("error", error) as Result<TResult, "error">;
}
};
constructor(status: TStatus, value: TStatus extends "success" ? TSuccessValue : unknown) {
this.status = status;
this.value = value;
}
map<TSuccessMapped = TSuccessValue>(handlers: {
success?: (value: TSuccessValue) => TSuccessMapped;
error?: (value: unknown) => unknown;
}): Result<TSuccessMapped> {
try {
switch (this.status) {
case "success": {
const mappedValue = handlers.success
? handlers.success(this.value as TSuccessValue)
: (this.value as TSuccessMapped);
return Result.success(mappedValue);
}
case "error": {
const mappedError = handlers.error
? handlers.error(this.value as unknown)
: (this.value as unknown);
return Result.error(mappedError);
}
}
} catch (mappingError) {
console.error("Error occurred while mapping Result:", mappingError);
return Result.error(mappingError);
}
}
unwrapOrThrow() {
switch (this.status) {
case "success":
return this.value as TSuccessValue;
case "error":
console.error("Error occurred while unwrapping Result:", this.value);
throw this.value;
}
}
unwrapOr<TDefaultValue>(defaultValue: TDefaultValue) {
switch (this.status) {
case "success":
return this.value as TSuccessValue;
case "error":
return defaultValue;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment