ts-error-as-value
Advanced tools
Comparing version 0.1.7 to 0.1.8
{ | ||
"name": "ts-error-as-value", | ||
"version": "0.1.7", | ||
"version": "0.1.8", | ||
"description": "Errors as values in typescript", | ||
"main": "lib/index.ts", | ||
"main": "lib/index.js", | ||
"keywords": ["result", "option", "rust", "kotlin", "errors", "errors as values", "typescript"], | ||
@@ -7,0 +7,0 @@ "types": "lib/index.d.ts", |
@@ -27,8 +27,8 @@ ### Typescript error as value | ||
``` | ||
This will make the functions ok, err and withResult, as well as the types Ok, Err and Result globally available | ||
This will make the functions ok, fail and withResult, as well as the types Ok, Fail and Result globally available | ||
--- | ||
## ok and err - Basic Usage | ||
Creating `Ok` and `Err` result objects | ||
## ok and fail - Basic Usage | ||
Creating `Ok` and `Fail` result objects | ||
```ts | ||
@@ -44,3 +44,3 @@ const { data, error } = ok("Hello"); | ||
```ts | ||
const { data, error } = err(new Error("Error")); | ||
const { data, error } = fail(new Error("Error")); | ||
if (error) { | ||
@@ -54,3 +54,3 @@ // do something with error | ||
Wrapping the returns from functions with `err` for errors, and `ok` for non-error so that the function calling it receives a `Result` type. | ||
Wrapping the returns from functions with `fail` for errors, and `ok` for non-error so that the function calling it receives a `Result` type. | ||
@@ -62,3 +62,3 @@ ```ts | ||
} | ||
return err(new Error("Method failed")); | ||
return fail(new Error("Method failed")); | ||
}; | ||
@@ -82,3 +82,3 @@ | ||
} | ||
return err(new Error("Method failed")); | ||
return fail(new Error("Method failed")); | ||
}; | ||
@@ -89,3 +89,3 @@ | ||
if (error) { | ||
return err(error); | ||
return fail(error); | ||
} | ||
@@ -109,3 +109,3 @@ return ok(data); | ||
} | ||
return err(new Error("Method failed")); | ||
return fail(new Error("Method failed")); | ||
}; | ||
@@ -122,3 +122,3 @@ | ||
if (error) { | ||
return err(error); | ||
return fail(error); | ||
} | ||
@@ -151,7 +151,7 @@ return ok(data); | ||
## Error stack | ||
One advantage of using errors as values is that we know exactly where an error was created and by whom. Taking advantage of this is still a WiP, however currently we keep track of information about all errors which we encountered in the current chain of Err results. | ||
One advantage of using errors as values is that we know exactly where an error was created and by whom. Taking advantage of this is still a WiP, however currently we keep track of information about all errors which we encountered in the current chain of Fail results. | ||
```ts | ||
const fn1 = () => err(new Error("Hello")); | ||
const fn1 = () => fail(new Error("Hello")); | ||
@@ -177,6 +177,5 @@ const fn2 = () => fn1().mapErr(() => new Error("World")); | ||
type Err<T, E extends Error = Error> = { | ||
type Fail<T, E extends Error = Error> = { | ||
data: never, | ||
error: E, | ||
get errorStack(): Error[], | ||
unwrap(): void, // Returns the value, but throws an error if the result is an Error | ||
@@ -191,3 +190,2 @@ unwrapOr<D>(defaultValue: D): D, // Returns the value or gives you a default value if it's an error | ||
error: never, | ||
get errorStack(): never, | ||
unwrap(): T, // Returns the value, but throws an error if the result is an Error | ||
@@ -200,3 +198,3 @@ unwrapOr<D>(defaultValue: D): T, // Returns the value or gives you a default value if it's an error | ||
type Result<T, E extends Error = ErrorResult> = | ||
| Err<T, E> | ||
| Fail<T, E> | ||
| Ok<T>; | ||
@@ -207,3 +205,3 @@ | ||
```ts | ||
function err<E extends Error>(error: E): Err<E>; | ||
function fail<E extends Error>(error: E): Fail<E>; | ||
function ok<T>(data: T): Ok<T>; | ||
@@ -210,0 +208,0 @@ ``` |
type Ok<T> = import(".").Ok<T>; | ||
type Err<E extends Error> = import(".").Err<E>; | ||
type None = import(".").None; | ||
type Fail<E extends Error> = import(".").Fail<E>; | ||
type Result<T, E extends Error> = import(".").Result<T, E>; | ||
declare function ok<T>(data: T): Ok<T>; | ||
declare function err<E extends Error>(error: E): Err<E> | ||
declare function fail<E extends Error>(error: E): Fail<E> | ||
declare function withResult<T, E extends Error, R>( | ||
@@ -10,0 +9,0 @@ fn: (...args: T[]) => R |
@@ -1,2 +0,2 @@ | ||
import { ok, err } from "."; | ||
import { ok, fail } from "."; | ||
import { withResult } from "./with-result"; | ||
@@ -6,8 +6,8 @@ | ||
(window as any).ok = ok; | ||
(window as any).err = err; | ||
(window as any).fail = fail; | ||
(window as any).withResult = withResult; | ||
} else { | ||
(globalThis as any).ok = ok; | ||
(globalThis as any).err = err; | ||
(globalThis as any).fail = fail; | ||
(globalThis as any).withResult = withResult; | ||
} |
@@ -1,13 +0,10 @@ | ||
import { ErrorResult, isErrorResult } from "./error-result"; | ||
export type None = null; | ||
export type Err<T, E extends Error = Error> = { | ||
data: never, | ||
export type Fail<E extends Error = Error> = { | ||
data: null, | ||
error: E, | ||
get errorStack(): Error[], | ||
unwrap(): void, // Returns the value, but throws an error if the result is an Error | ||
unwrapOr<D>(defaultValue: D): D, // Returns the value or gives you a default value if it's an error | ||
mapErr<E2 extends Error>(fn: (err: E) => E2): Err<T, E2>, // If the result is an error, map the error to another error | ||
andThen<N>(fn: (data: never) => N): Err<T, E> // If the result is not an error, map the data in it | ||
mapFail<E2 extends Error>(fn: (fail: E) => E2): Fail<E2>, // If the result is an error, map the error to another error | ||
andThen<N>(fn: (data: never) => N): Fail<E> // If the result is not an error, map the data in it | ||
}; | ||
@@ -17,7 +14,6 @@ | ||
data: T, | ||
error: never, | ||
get errorStack(): never, | ||
error: null, | ||
unwrap(): T, // Returns the value, but throws an error if the result is an Error | ||
unwrapOr<D>(defaultValue: D): T, // Returns the value or gives you a default value if it's an error | ||
mapErr<E2 extends Error>(fn: (err: never) => E2): Ok<T>, // If the result is an error, map the error to another error | ||
mapFail<E2 extends Error>(fn: (fail: never) => E2): Ok<T>, // If the result is an error, map the error to another error | ||
andThen<N>(fn: (data: T) => N): Ok<N> // If the result is not an error, map the data in it | ||
@@ -27,44 +23,16 @@ }; | ||
export type Result< | ||
T, E extends Error = ErrorResult | ||
> = Err<T, E> | Ok<T>; | ||
T, E extends Error = Error | ||
> = Fail<E> | Ok<T>; | ||
export const err = <E extends Error>( | ||
export const fail = <E extends Error>( | ||
error: E | ||
): Err<None, E> => { | ||
if (isErrorResult(error)) { | ||
return { | ||
data: null as never, | ||
error: ErrorResult.fromExistingResult(error), | ||
get errorStack() { | ||
return error._errorStack; | ||
}, | ||
unwrap(): void { | ||
throw error; | ||
}, | ||
mapErr<E2 extends Error>(fn: (err: E) => E2): Err<None, E2> { | ||
return removeLastErrorStackItem(err<E2>(ErrorResult.new(error, fn(error)))); | ||
}, | ||
unwrapOr<D>(defaultValue: D): D { | ||
return defaultValue; | ||
}, | ||
andThen(): Err<None, E> { | ||
return this; | ||
} | ||
}; | ||
} | ||
const errorResult = ErrorResult.fromError(error); | ||
): Fail<E> => { | ||
return { | ||
data: null as never, | ||
error: errorResult, | ||
get errorStack() { | ||
if (!isErrorResult(errorResult)) { | ||
return []; | ||
} | ||
return errorResult._errorStack; | ||
}, | ||
data: null, | ||
error: error, | ||
unwrap() { | ||
throw error; | ||
}, | ||
mapErr<E2 extends Error>(fn: (err: E) => E2): Err<None, E2> { | ||
return removeLastErrorStackItem(err<E2>(ErrorResult.new(error, fn(error)))); | ||
mapFail<E2 extends Error>(fn: (err: E) => E2): Fail<E2> { | ||
return fail<E2>(fn(error)); | ||
}, | ||
@@ -74,3 +42,3 @@ unwrapOr<D>(defaultValue: D): D { | ||
}, | ||
andThen(): Err<None, E> { | ||
andThen(): Fail<E> { | ||
return this; | ||
@@ -85,10 +53,7 @@ } | ||
data, | ||
error: null as never, | ||
get errorStack() { | ||
return [] as never; | ||
}, | ||
error: null, | ||
unwrap(): T { | ||
return data; | ||
}, | ||
mapErr(): Ok<T> { | ||
mapFail(): Ok<T> { | ||
return this; | ||
@@ -104,9 +69,1 @@ }, | ||
const removeLastErrorStackItem = <T, E extends Error>(result: Err<T, E>): Err<T, E> => { | ||
if (result.error) { | ||
const newErrorResult: any = { ...result.error }; | ||
newErrorResult._errorStack = newErrorResult._errorStack.slice(0, -1); | ||
return { ...result, error: newErrorResult }; | ||
} | ||
return result; | ||
}; |
@@ -1,3 +0,2 @@ | ||
import { err, Err, Ok, ok } from "../src"; | ||
import { isErrorResult } from "./error-result"; | ||
import { fail, Fail, Result, Ok, ok } from "../src"; | ||
@@ -7,18 +6,10 @@ | ||
describe("Err type", () => { | ||
let errorInstance: Err<null>; | ||
describe("Fail type", () => { | ||
let errorInstance: Result<string, Error>; | ||
const testError = new Error("Test error"); | ||
beforeEach(() => { | ||
errorInstance = err(testError); | ||
errorInstance = fail(testError); | ||
}); | ||
it("should return error for Err type", () => { | ||
expect(isErrorResult(errorInstance.error)).toBeTruthy(); | ||
}); | ||
it("should return error stack for Err type", () => { | ||
expect(errorInstance.errorStack).toEqual(expect.arrayContaining([ testError ])); | ||
}); | ||
it("should throw error on unwrap for Err type", () => { | ||
@@ -34,6 +25,5 @@ expect(() => errorInstance.unwrap()).toThrow(testError); | ||
const newError = new Error("New error"); | ||
const { error } = errorInstance.mapErr(() => newError); | ||
expect(isErrorResult(error)).toBeTruthy(); | ||
if (isErrorResult(error)) { | ||
expect(error._errorStack[error._errorStack.length - 1].message).toBe(newError.message); | ||
const { error } = errorInstance.mapFail(() => newError); | ||
if (error) { | ||
expect(error.message).toBe(newError.message); | ||
} | ||
@@ -73,3 +63,3 @@ }); | ||
it("should return itself on mapErr for Ok type", () => { | ||
const result = okInstance.mapErr(() => new Error("New error")); | ||
const result = okInstance.mapFail(() => new Error("New error")); | ||
expect(JSON.stringify(result)).toEqual(JSON.stringify(okInstance)); | ||
@@ -76,0 +66,0 @@ }); |
@@ -1,2 +0,2 @@ | ||
import { err, ok, Result, Ok, Err } from "./index"; | ||
import { fail, ok, Result, Ok, Fail } from "./index"; | ||
@@ -6,3 +6,3 @@ export const isPromise = <T>(value: T | Promise<T>): value is Promise<T> => | ||
/** Function which wraps another function and returns an Err result if the wrapped function throws an error, | ||
/** Function which wraps another function and returns a Fail result if the wrapped function throws an error, | ||
* and returns an Ok result if the wrapped function does not. */ | ||
@@ -19,3 +19,3 @@ export const withResult = <T, E extends Error, R>( | ||
.then(value => ok(value) as Ok<typeof value>) | ||
.catch(e => err(e) as Err<E>) as (R extends Promise<infer u> ? Promise<Result<u, E>> : Result<R, E>); | ||
.catch(e => fail(e) as Fail<E>) as (R extends Promise<infer u> ? Promise<Result<u, E>> : Result<R, E>); | ||
} | ||
@@ -25,3 +25,3 @@ return ok(data) as any; | ||
const e = error instanceof Error ? error : new Error("Unknown error"); | ||
return err(e) as any; | ||
return fail(e) as any; | ||
} | ||
@@ -28,0 +28,0 @@ }; |
@@ -26,3 +26,3 @@ // Assuming a jest-like syntax for demonstration purposes. | ||
it("should return Err for errors", () => { | ||
it("should return Fail for errors", () => { | ||
const errorFunc = (): Result<null, Error> => { | ||
@@ -45,3 +45,3 @@ throw new Error("Oops!"); | ||
it("should return Err for rejected promises", async () => { | ||
it("should return Fail for rejected promises", async () => { | ||
const errorAsyncFunc = async () => { | ||
@@ -48,0 +48,0 @@ throw new Error("Oops async!"); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
22293
23
455
217