main
ts 242 lines 6.2 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 // Direct translation of Rust's Result type, although some ownership related methods are omitted.
9 export interface Result<T, E> {
10 /*
11 * Maps a `Result<T, E>` to `Result<U, E>` by applying a function to a contained `Ok` value,
12 * leaving an `Err` value untouched.
13 *
14 * This function can be used to compose the results of two functions.
15 */
16 map<U>(fn: (val: T) => U): Result<U, E>;
17 /*
18 * Maps a `Result<T, E>` to `Result<T, F>` by applying a function to a contained `Err` value,
19 * leaving an `Ok` value untouched.
20 *
21 * This function can be used to pass through a successful result while handling an error.
22 */
23 mapErr<F>(fn: (val: E) => F): Result<T, F>;
24 /*
25 * Returns the provided default (if `Err`), or applies a function to the contained value
26 * (if `Ok`).
27 *
28 * Arguments passed to {@link mapOr} are eagerly evaluated; if you are passing the result of a
29 * function call, it is recommended to use {@link mapOrElse}, which is lazily evaluated.
30 */
31 mapOr<U>(fallback: U, fn: (val: T) => U): U;
32 /*
33 * Maps a `Result<T, E>` to `U` by applying fallback function default to a contained `Err` value,
34 * or function `fn` to a contained `Ok` value.
35 *
36 * This function can be used to unpack a successful result while handling an error.
37 */
38 mapOrElse<U>(fallback: () => U, fn: (val: T) => U): U;
39 /*
40 * Calls `fn` if the result is `Ok`, otherwise returns the `Err` value of self.
41 *
42 * This function can be used for control flow based on Result values.
43 */
44 andThen<U>(fn: (val: T) => Result<U, E>): Result<U, E>;
45 /*
46 * Returns res if the result is `Ok`, otherwise returns the `Err` value of self.
47 *
48 * Arguments passed to {@link and} are eagerly evaluated; if you are passing the result of a
49 * function call, it is recommended to use {@link andThen}, which is lazily evaluated.
50 */
51 and<U>(res: Result<U, E>): Result<U, E>;
52 /*
53 * Returns `res` if the result is `Err`, otherwise returns the `Ok` value of self.
54 *
55 * Arguments passed to {@link or} are eagerly evaluated; if you are passing the result of a
56 * function call, it is recommended to use {@link orElse}, which is lazily evaluated.
57 */
58 or(res: Result<T, E>): Result<T, E>;
59 /*
60 * Calls `fn` if the result is `Err`, otherwise returns the `Ok` value of self.
61 *
62 * This function can be used for control flow based on result values.
63 */
64 orElse<F>(fn: (val: E) => Result<T, F>): Result<T, F>;
65 // Returns `true` if the result is `Ok`.
66 isOk(): this is OkImpl<T>;
67 // Returns `true` if the result is `Err`.
68 isErr(): this is ErrImpl<E>;
69 // Returns the contained `Ok` value or throws.
70 expect(msg: string): T;
71 // Returns the contained `Err` value or throws.
72 expectErr(msg: string): E;
73 // Returns the contained `Ok` value.
74 unwrap(): T;
75 /*
76 * Returns the contained `Ok` value or a provided default.
77 *
78 * Arguments passed to {@link unwrapOr} are eagerly evaluated; if you are passing the result of a
79 * function call, it is recommended to use {@link unwrapOrElse}, which is lazily evaluated.
80 */
81 unwrapOr(fallback: T): T;
82 // Returns the contained `Ok` value or computes it from a closure.
83 unwrapOrElse(fallback: (val: E) => T): T;
84 // Returns the contained `Err` value or throws.
85 unwrapErr(): E;
86 }
87
88 export function Ok<T>(val: T): OkImpl<T> {
89 return new OkImpl(val);
90 }
91
92 class OkImpl<T> implements Result<T, never> {
93 #val: T;
94 constructor(val: T) {
95 this.#val = val;
96 }
97
98 map<U>(fn: (val: T) => U): Result<U, never> {
99 return new OkImpl(fn(this.#val));
100 }
101
102 mapErr<F>(_fn: (val: never) => F): Result<T, F> {
103 return this;
104 }
105
106 mapOr<U>(_fallback: U, fn: (val: T) => U): U {
107 return fn(this.#val);
108 }
109
110 mapOrElse<U>(_fallback: () => U, fn: (val: T) => U): U {
111 return fn(this.#val);
112 }
113
114 andThen<U>(fn: (val: T) => Result<U, never>): Result<U, never> {
115 return fn(this.#val);
116 }
117
118 and<U>(res: Result<U, never>): Result<U, never> {
119 return res;
120 }
121
122 or(_res: Result<T, never>): Result<T, never> {
123 return this;
124 }
125
126 orElse<F>(_fn: (val: never) => Result<T, F>): Result<T, F> {
127 return this;
128 }
129
130 isOk(): this is OkImpl<T> {
131 return true;
132 }
133
134 isErr(): this is ErrImpl<never> {
135 return false;
136 }
137
138 expect(_msg: string): T {
139 return this.#val;
140 }
141
142 expectErr(msg: string): never {
143 throw new Error(`${msg}: ${this.#val}`);
144 }
145
146 unwrap(): T {
147 return this.#val;
148 }
149
150 unwrapOr(_fallback: T): T {
151 return this.#val;
152 }
153
154 unwrapOrElse(_fallback: (val: never) => T): T {
155 return this.#val;
156 }
157
158 unwrapErr(): never {
159 if (this.#val instanceof Error) {
160 throw this.#val;
161 }
162 throw new Error(`Can't unwrap \`Ok\` to \`Err\`: ${this.#val}`);
163 }
164 }
165
166 export function Err<E>(val: E): ErrImpl<E> {
167 return new ErrImpl(val);
168 }
169
170 class ErrImpl<E> implements Result<never, E> {
171 #val: E;
172 constructor(val: E) {
173 this.#val = val;
174 }
175
176 map<U>(_fn: (val: never) => U): Result<U, E> {
177 return this;
178 }
179
180 mapErr<F>(fn: (val: E) => F): Result<never, F> {
181 return new ErrImpl(fn(this.#val));
182 }
183
184 mapOr<U>(fallback: U, _fn: (val: never) => U): U {
185 return fallback;
186 }
187
188 mapOrElse<U>(fallback: () => U, _fn: (val: never) => U): U {
189 return fallback();
190 }
191
192 andThen<U>(_fn: (val: never) => Result<U, E>): Result<U, E> {
193 return this;
194 }
195
196 and<U>(_res: Result<U, E>): Result<U, E> {
197 return this;
198 }
199
200 or(res: Result<never, E>): Result<never, E> {
201 return res;
202 }
203
204 orElse<F>(fn: (val: E) => ErrImpl<F>): Result<never, F> {
205 return fn(this.#val);
206 }
207
208 isOk(): this is OkImpl<never> {
209 return false;
210 }
211
212 isErr(): this is ErrImpl<E> {
213 return true;
214 }
215
216 expect(msg: string): never {
217 throw new Error(`${msg}: ${this.#val}`);
218 }
219
220 expectErr(_msg: string): E {
221 return this.#val;
222 }
223
224 unwrap(): never {
225 if (this.#val instanceof Error) {
226 throw this.#val;
227 }
228 throw new Error(`Can't unwrap \`Err\` to \`Ok\`: ${this.#val}`);
229 }
230
231 unwrapOr<T>(fallback: T): T {
232 return fallback;
233 }
234
235 unwrapOrElse<T>(fallback: (val: E) => T): T {
236 return fallback(this.#val);
237 }
238
239 unwrapErr(): E {
240 return this.#val;
241 }
242 }