resultfier 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bun.lock +30 -0
- package/lib/core/err.ts +93 -0
- package/lib/core/index.ts +3 -0
- package/lib/core/ok.ts +93 -0
- package/lib/core/result.ts +78 -0
- package/package.json +27 -0
- package/tsconfig.json +35 -0
package/bun.lock
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"workspaces": {
|
|
4
|
+
"": {
|
|
5
|
+
"name": "resultfier",
|
|
6
|
+
"devDependencies": {
|
|
7
|
+
"@types/bun": "latest",
|
|
8
|
+
"typescript": "^5.9.2",
|
|
9
|
+
},
|
|
10
|
+
"peerDependencies": {
|
|
11
|
+
"typescript": "^5.9.2",
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
"packages": {
|
|
16
|
+
"@types/bun": ["@types/bun@1.2.21", "", { "dependencies": { "bun-types": "1.2.21" } }, "sha512-NiDnvEqmbfQ6dmZ3EeUO577s4P5bf4HCTXtI6trMc6f6RzirY5IrF3aIookuSpyslFzrnvv2lmEWv5HyC1X79A=="],
|
|
17
|
+
|
|
18
|
+
"@types/node": ["@types/node@24.3.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g=="],
|
|
19
|
+
|
|
20
|
+
"@types/react": ["@types/react@19.1.12", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w=="],
|
|
21
|
+
|
|
22
|
+
"bun-types": ["bun-types@1.2.21", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-sa2Tj77Ijc/NTLS0/Odjq/qngmEPZfbfnOERi0KRUYhT9R8M4VBioWVmMWE5GrYbKMc+5lVybXygLdibHaqVqw=="],
|
|
23
|
+
|
|
24
|
+
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
|
25
|
+
|
|
26
|
+
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
|
|
27
|
+
|
|
28
|
+
"undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="],
|
|
29
|
+
}
|
|
30
|
+
}
|
package/lib/core/err.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { type Result, ResultBase } from "./result";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Represents an error result containing an error value.
|
|
5
|
+
*/
|
|
6
|
+
export class Err<E> extends ResultBase<never, E> {
|
|
7
|
+
readonly _tag = "err" as const;
|
|
8
|
+
readonly isOk = false;
|
|
9
|
+
readonly isErr = true;
|
|
10
|
+
|
|
11
|
+
constructor(readonly error: E) {
|
|
12
|
+
super();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Maps the value type, but since this is `Err`, it's a no-op.
|
|
17
|
+
*/
|
|
18
|
+
map<U>(_fn: (value: never) => U): Err<E> {
|
|
19
|
+
return this;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Maps the contained error using the provided function.
|
|
24
|
+
* Since this is `Err`, the function is always applied.
|
|
25
|
+
*/
|
|
26
|
+
mapErr<F>(fn: (error: E) => F): Err<F> {
|
|
27
|
+
return new Err(fn(this.error));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Throws an error since this is `Err`, not `Ok`.
|
|
32
|
+
*/
|
|
33
|
+
unwrap(): never {
|
|
34
|
+
throw new Error(`Called unwrap() on an Err value: ${this.error}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Returns the contained error.
|
|
39
|
+
*/
|
|
40
|
+
unwrapErr(): E {
|
|
41
|
+
return this.error;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Returns the provided default value since this is `Err`.
|
|
46
|
+
*/
|
|
47
|
+
unwrapOr<T>(defaultValue: T): T {
|
|
48
|
+
return defaultValue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Computes and returns the fallback value using the provided function.
|
|
53
|
+
*/
|
|
54
|
+
unwrapOrElse<T>(fn: (error: E) => T): T {
|
|
55
|
+
return fn(this.error);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Returns this `Err` unchanged since there's no value to chain.
|
|
60
|
+
*/
|
|
61
|
+
andThen<U>(_fn: (value: never) => Result<U, E>): Err<E> {
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Always returns false since this is `Err`, not `Ok`.
|
|
67
|
+
*/
|
|
68
|
+
contains(_value: never): boolean {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Checks if the contained error matches the provided error.
|
|
74
|
+
*/
|
|
75
|
+
containsErr(error: E): boolean {
|
|
76
|
+
return this.error === error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Creates a new `Err` result with the given error.
|
|
82
|
+
*/
|
|
83
|
+
export function err<E>(error: E): Err<E> {
|
|
84
|
+
return new Err(error);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Type guard to check if a result is `Err`.
|
|
89
|
+
* @deprecated use `.isErr` instead
|
|
90
|
+
*/
|
|
91
|
+
export function isErr<T, E>(result: Result<T, E>): result is Err<E> {
|
|
92
|
+
return result.isErr;
|
|
93
|
+
}
|
package/lib/core/ok.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { type Result, ResultBase } from "./result";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Represents a successful result containing a value.
|
|
5
|
+
*/
|
|
6
|
+
export class Ok<T> extends ResultBase<T, never> {
|
|
7
|
+
readonly _tag = "ok" as const;
|
|
8
|
+
readonly isOk = true;
|
|
9
|
+
readonly isErr = false;
|
|
10
|
+
|
|
11
|
+
constructor(readonly value: T) {
|
|
12
|
+
super();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Maps the contained value using the provided function.
|
|
17
|
+
* Since this is `Ok`, the function is always applied.
|
|
18
|
+
*/
|
|
19
|
+
map<U>(fn: (value: T) => U): Ok<U> {
|
|
20
|
+
return new Ok(fn(this.value));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Maps the error type, but since this is `Ok`, it's a no-op.
|
|
25
|
+
*/
|
|
26
|
+
mapErr<F>(_fn: (error: never) => F): Ok<T> {
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Returns the contained value.
|
|
32
|
+
*/
|
|
33
|
+
unwrap(): T {
|
|
34
|
+
return this.value;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Throws an error since this is Ok, not Err.
|
|
39
|
+
*/
|
|
40
|
+
unwrapErr(): never {
|
|
41
|
+
throw new Error(`Called unwrapErr() on an Ok value: ${this.value}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Returns the contained value, ignoring the default.
|
|
46
|
+
*/
|
|
47
|
+
unwrapOr(_defaultValue: T): T {
|
|
48
|
+
return this.value;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Returns the contained value, ignoring the fallback function.
|
|
53
|
+
*/
|
|
54
|
+
unwrapOrElse(_fn: (error: never) => T): T {
|
|
55
|
+
return this.value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Applies the function to the contained value and returns the result.
|
|
60
|
+
*/
|
|
61
|
+
andThen<U>(fn: (value: T) => Result<U, never>): Result<U, never> {
|
|
62
|
+
return fn(this.value);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Checks if the contained value matches the provided value.
|
|
67
|
+
*/
|
|
68
|
+
contains(value: T): boolean {
|
|
69
|
+
return this.value === value;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Always returns false since this is `Ok`, not `Err`.
|
|
74
|
+
*/
|
|
75
|
+
override containsErr(_error: never): false {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Creates a new `Ok` result with the given value.
|
|
82
|
+
*/
|
|
83
|
+
export function ok<T>(value: T): Ok<T> {
|
|
84
|
+
return new Ok(value);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Type guard to check if a result is `Ok`.
|
|
89
|
+
* @deprecated use `.isOk` instead
|
|
90
|
+
*/
|
|
91
|
+
export function isOk<T, E>(result: Result<T, E>): result is Ok<T> {
|
|
92
|
+
return result.isOk;
|
|
93
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Err } from "./err";
|
|
2
|
+
import type { Ok } from "./ok";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Represents a Result type that can either be a success (`Ok`) or an error (`Err`).
|
|
6
|
+
* This is an abstract base class that provides common functionality for both variants.
|
|
7
|
+
*/
|
|
8
|
+
export abstract class ResultBase<T, E> {
|
|
9
|
+
/**
|
|
10
|
+
* Type guard to check if the result is an `Ok` variant.
|
|
11
|
+
*/
|
|
12
|
+
abstract readonly isOk: boolean;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Type guard to check if the result is an `Err` variant.
|
|
16
|
+
*/
|
|
17
|
+
abstract readonly isErr: boolean;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Maps a `Result<T, E>` to `Result<U, E>` by applying a function to a contained `Ok` value,
|
|
21
|
+
* leaving an `Err` value untouched.
|
|
22
|
+
*/
|
|
23
|
+
abstract map<U>(fn: (value: T) => U): Result<U, E>;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Maps a `Result<T, E>` to `Result<T, F>` by applying a function to a contained `Err` value,
|
|
27
|
+
* leaving an `Ok` value untouched.
|
|
28
|
+
*/
|
|
29
|
+
abstract mapErr<F>(fn: (error: E) => F): Result<T, F>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Returns the contained `Ok` value, consuming the self value.
|
|
33
|
+
* Throws an error if the result is `Err`.
|
|
34
|
+
*/
|
|
35
|
+
abstract unwrap(): T;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Returns the contained `Err` value, consuming the self value.
|
|
39
|
+
* Throws an error if the result is Ok.
|
|
40
|
+
*/
|
|
41
|
+
abstract unwrapErr(): E;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Returns the contained `Ok` value or a provided default.
|
|
45
|
+
*/
|
|
46
|
+
abstract unwrapOr(defaultValue: T): T;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Returns the contained `Ok` value or computes it from a closure.
|
|
50
|
+
*/
|
|
51
|
+
abstract unwrapOrElse(fn: (error: E) => T): T;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Calls the provided function with the contained value and returns the result.
|
|
55
|
+
* If the result is `Err`, the function is not called and the `Err` is returned.
|
|
56
|
+
*/
|
|
57
|
+
abstract andThen<U>(fn: (value: T) => Result<U, E>): Result<U, E>;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Returns true if the result is `Ok` and the value inside of it matches a predicate.
|
|
61
|
+
*/
|
|
62
|
+
abstract contains(value: T): boolean;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Returns true if the result is `Err` and the error inside of it matches a predicate.
|
|
66
|
+
*/
|
|
67
|
+
abstract containsErr(error: E): boolean;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Type alias for a `Result` that can be either `Ok<T>` or `Err<E>`.
|
|
72
|
+
*/
|
|
73
|
+
export type Result<T, E> = Ok<T> | Err<E>;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Type alias for an async `Result` (Promise-wrapped `Result`).
|
|
77
|
+
*/
|
|
78
|
+
export type AsyncResult<T, E> = Promise<Result<T, E>>;
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "resultfier",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A TypeScript implementation of Rust-like Result type for better error handling",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc",
|
|
8
|
+
"prepublishOnly": "bun run build"
|
|
9
|
+
},
|
|
10
|
+
"author": "Vitor Koch <vitorgabrielkoch@gmail.com>",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/vitorkoch/resultfier.git"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/vitorkoch/resultfier/issues"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/vitorkoch/resultfier#readme",
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/bun": "latest",
|
|
22
|
+
"typescript": "^5.9.2"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"typescript": "^5"
|
|
26
|
+
}
|
|
27
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Output configuration for npm publishing
|
|
4
|
+
"outDir": "./out",
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"declarationMap": true,
|
|
7
|
+
"sourceMap": true,
|
|
8
|
+
"rootDir": "lib/",
|
|
9
|
+
|
|
10
|
+
// Module system
|
|
11
|
+
"target": "ES2020",
|
|
12
|
+
"module": "ESNext",
|
|
13
|
+
"moduleResolution": "node",
|
|
14
|
+
"esModuleInterop": true,
|
|
15
|
+
"allowSyntheticDefaultImports": true,
|
|
16
|
+
|
|
17
|
+
// Type checking
|
|
18
|
+
"strict": true,
|
|
19
|
+
"noImplicitAny": true,
|
|
20
|
+
"strictNullChecks": true,
|
|
21
|
+
"strictFunctionTypes": true,
|
|
22
|
+
"noImplicitReturns": true,
|
|
23
|
+
"noFallthroughCasesInSwitch": true,
|
|
24
|
+
"noUncheckedIndexedAccess": true,
|
|
25
|
+
|
|
26
|
+
// Additional checks
|
|
27
|
+
"skipLibCheck": true,
|
|
28
|
+
"forceConsistentCasingInFileNames": true,
|
|
29
|
+
|
|
30
|
+
// Library
|
|
31
|
+
"lib": ["ES2020"]
|
|
32
|
+
},
|
|
33
|
+
"include": ["**/*.ts"],
|
|
34
|
+
"exclude": ["node_modules", "out"]
|
|
35
|
+
}
|