type ThrowType = (this: Result, message?: string) => T; type ElseType = (this: Result, callback: (error: E) => T) => T; type OrType = (this: Result, orValue: T) => T; type AndType = (this: Result, callback: (result: T) => void) => Result; type ThrowMethod = { /** * @method `throw` returns unwrapped result data or throws an error. If the error message wasn't provided and the type of error is `void` or `undefined` will use the default error message. * @param {string | undefined} message - optional message parameter to be used as an error message (if an `Error` was provided for `E` type it's message will be overwritten by this custom message) * @throws provided error or a common `Error` with the default message * @returns result data with the type `T`, provided in `Result` * @example * ```ts * function toNumber(str: string): Result { * const parseResult = Number(str); * * if (isNaN(parseResult)) { * return Err("Couldn't parse a string"); * } * * return Ok(parseResult); * } * * function getNumber(): number { * return toNumber("123").throw(); // Returns 123 * } * * function getNumber(): number { * return toNumber("abc").throw(); // Throws Error("Couldn't parse a string") * } * * ``` * */ throw: ThrowType; }; type OrMethod = { /** * @method `or` returns unwrapped result data or returns a back-up value * @param {T} orValue - back-up value to be used in case there was an error. Value type should match `T` type specified in `Result` * @returns result data with the type `T`, provided in `Result` * @example * ```ts * function getStatusCode(): Result { * const statusCode = Math.floor(Math.random() * 100); * * if (statusCode > 200 && statusCode < 300) { * return Ok(statusCode); * } * * return Err("Wrong status code"); * } * * function obtainStatus(): number { * return getStatusCode().or(0); * } * * ``` * */ or: OrType; }; type ElseMethod = { /** * @method `else` returns unwrapped result data or executes a callback which has an access to an error. * @param {(error: E) => T} callback - callback which will be executed if result ok field will is false. Callback is provided with `error` argument with the error type provided as `E` in `Result`, should return value of the type `T` * @returns result data with the type `T`, provided in `Result` * @example * ```ts * function getStatusCode(): Result { * const statusCode = Math.floor(Math.random() * 100); * * if (statusCode > 200 && statusCode < 300) { * return Ok(statusCode); * } * * if (statusCode < 200) { * return Err("Low"); * } * * return Err("High"); * } * * function obtainStatus(): number { * return getStatusCode().else((error) => { * if (error === "Low") { * return 0; * } * * return 1000; * }); * } * * ``` * */ else: ElseType; }; type AndMethod = { /** * @method `and` handles result in a callback ignoring the error * @param {(result: T) => void} callback - callback which will be executed if result ok field will is true. Callback is provided with `result` argument with the data type provided as `T` in `Result` * @returns `Result` allowing for chaining * @example * ```ts * function tryReadFile(): Result { * const text = fs.readFile('~/file.txt'); * * if (!text) { * return Err(); * } * * return Ok(text); * } * * tryReadFile.and((text) => { * console.log(text); * }) * ``` *
* * @example * ```ts * function toNumber(str: string): Result { * const parseResult = Number(str); * * if (isNaN(parseResult)) { * return Err(new Error(`Couldn't convert ${str} to number`)); * } * * return Ok(parseResult); * } * * // Chaining and method * toNumber("123") * .and((number) => { * console.log(number); * }) * .else((error) => { * console.error(error); * }); * ``` * */ and: AndType; }; type ResultMethods = ThrowMethod & ElseMethod & OrMethod & AndMethod; export type ErrType = string | Error | undefined | void; /** * @type `Result` - is used to signify that the operation may fail. `T` is generic return type of the value, it can be any type, `E` is an error type it's constrained by `string | Error | undefined | void`. * * Value, returned from a function with a type `Result` will contain an `ok` boolean field signifying success or fail, if `ok` is `true`, then `Result` will also contain `data` field with type `T`, otherwise it will contain an `error` field with type `E`. * * To be able to return a correct value from a function with return type `Result` use methods `Ok(T)`, `Err(E)`. * * *Additionally* `Result` contains a number of helper methods such as `throw()`, `or()`, `else()` to make handling result as simple as possible * @example * ```ts * function toNumber(str: string): Result { * const parseResult = Number(str); * * if (isNaN(parseResult)) { * return Err(new Error(`Couldn't convert ${str} to number`)); * } * * return Ok(parseResult); * } * * toNumber("123"); // -> {ok: true, data: 123} * toNumber("abc"); // -> {ok: false, error: Error("Couldn't convert abc to number")} * ``` * */ export type Result = ({ ok: true; data: T; } & ResultMethods) | ({ ok: false; error: E; } & ResultMethods); export {};