Skip to content

Commit 8bdf089

Browse files
committed
feat: mimic Promise api
1 parent aee48fb commit 8bdf089

1 file changed

Lines changed: 33 additions & 65 deletions

File tree

src/try.ts

Lines changed: 33 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,35 @@
1-
interface ITry<A> {
2-
ok: boolean;
1+
abstract class TryOutcome<A> {
2+
abstract readonly ok: boolean;
33

4-
then<B = A>(onsuccess: ((value: A) => B | Try<B>) | undefined | null): Try<B>;
5-
catch<B = never>(
4+
abstract then<B = A>(
5+
onsuccess: ((value: A) => B | Try<B>) | undefined | null
6+
): Try<B>;
7+
abstract catch<B = never>(
68
onfailure: ((reason: unknown) => B | Try<B>) | undefined | null
79
): Try<A | B>;
8-
finally(onfinally?: (() => void) | undefined | null): Try<A>;
910

10-
readonly [Symbol.toStringTag]: string;
11-
}
11+
get [Symbol.toStringTag]() {
12+
return "Try";
13+
}
1214

13-
export class Success<A> implements ITry<A> {
14-
readonly ok = true;
15+
finally(onfinally?: (() => void) | undefined | null): Try<A> {
16+
if (!onfinally) return this as unknown as Try<A>;
1517

16-
constructor(readonly value: A) {
17-
return this;
18+
try {
19+
onfinally();
20+
} catch (_) {
21+
// Ignore errors in finally, to match Promise.finally() behavior
22+
}
23+
24+
return this as unknown as Try<A>;
1825
}
26+
}
1927

20-
get [Symbol.toStringTag]() {
21-
return "Try";
28+
export class Success<A> extends TryOutcome<A> {
29+
readonly ok = true;
30+
31+
constructor(public readonly value: A) {
32+
super();
2233
}
2334

2435
then<B = A>(
@@ -43,30 +54,15 @@ export class Success<A> implements ITry<A> {
4354
catch<B = never>(
4455
onfailure: ((reason: unknown) => B | Try<B>) | undefined | null
4556
): Try<A | B> {
46-
return this as unknown as Try<A | B>;
47-
}
48-
49-
finally(onfinally?: (() => void) | undefined | null): Try<A> {
50-
if (!onfinally) return this;
51-
52-
try {
53-
onfinally();
54-
return this;
55-
} catch (error) {
56-
return new Failure(error);
57-
}
57+
return this;
5858
}
5959
}
6060

61-
export class Failure<A> implements ITry<A> {
61+
export class Failure<A> extends TryOutcome<A> {
6262
readonly ok = false;
6363

64-
constructor(readonly error: unknown) {
65-
return this;
66-
}
67-
68-
get [Symbol.toStringTag]() {
69-
return "Try";
64+
constructor(public readonly error: unknown) {
65+
super();
7066
}
7167

7268
then<B = A>(
@@ -93,17 +89,6 @@ export class Failure<A> implements ITry<A> {
9389
return new Failure(error);
9490
}
9591
}
96-
97-
finally(onfinally?: (() => void) | undefined | null): Try<A> {
98-
if (!onfinally) return this;
99-
100-
try {
101-
onfinally();
102-
return this;
103-
} catch (error) {
104-
return new Failure(error);
105-
}
106-
}
10792
}
10893

10994
export type Try<A> = Success<A> | Failure<A>;
@@ -135,7 +120,7 @@ const TryImplementation: Omit<TryConstructor, never> = {
135120
try {
136121
return new Success<A>(value());
137122
} catch (error) {
138-
return new Failure<A>(error as A);
123+
return new Failure<A>(error);
139124
}
140125
},
141126
success<A>(value: A | Try<A>): Try<Unwrapped<A>> {
@@ -144,15 +129,10 @@ const TryImplementation: Omit<TryConstructor, never> = {
144129
() => TryImplementation.unwrap(value) as Unwrapped<A>
145130
);
146131
}
132+
147133
return new Success(value) as unknown as Try<Unwrapped<A>>;
148134
},
149135
failure<A = never>(reason: unknown): Try<A> {
150-
if (TryImplementation.isTry(reason)) {
151-
return TryImplementation.apply(
152-
() => TryImplementation.unwrap(reason) as A
153-
);
154-
}
155-
156136
return new Failure(reason);
157137
},
158138
unwrap<A>(value: Try<A>): A {
@@ -195,26 +175,14 @@ export const Try = Object.assign(function <A>(
195175

196176
if (v.ok && isPromise(v.value)) {
197177
return v.value;
198-
} else {
199-
return v as Try<A>;
200178
}
179+
180+
return v as Try<A>;
201181
},
202182
TryImplementation) as TryConstructor;
203183

204-
/* Result Types */
205-
type ResultOk<T> = {
206-
ok: true;
207-
value: T;
208-
};
209-
210-
type ResultError<E = unknown> = {
211-
ok: false;
212-
error: E;
213-
};
214-
215-
export type Result<T, E = unknown> = ResultOk<T> | ResultError<E>;
184+
/* Helpers */
216185

217-
/* Helper */
218186
function isPromise(value: unknown): value is Promise<unknown> {
219187
return Object.prototype.toString.call(value) === "[object Promise]";
220188
}

0 commit comments

Comments
 (0)