Skip to content

Commit 7fe328d

Browse files
committed
Improve Result type inference for ok and err functions
Changed the `ok()` function to return `Result<T, never>` and the `err()` function to return `Result<never, E>` to ensure correct type inference.
1 parent 780b6f0 commit 7fe328d

2 files changed

Lines changed: 28 additions & 26 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@evolu/common": major
3+
---
4+
5+
Changed `ok()` to return `Result<T, never>` and `err()` to return `Result<never, E>` for correct type inference.

packages/common/src/Result.ts

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,7 @@ import type { Task } from "./Task.js";
5252
* }
5353
* ```
5454
*
55-
* ### Example
56-
*
57-
* Safe JSON parsing:
55+
* ## Example
5856
*
5957
* ```ts
6058
* interface ParseJsonError {
@@ -92,10 +90,9 @@ import type { Task } from "./Task.js";
9290
* ```
9391
*
9492
* `trySync` makes synchronous code that can throw safe. For asynchronous code,
95-
* use {@link tryAsync}. For lazy, cancellable async operations, see
96-
* {@link Task}.
93+
* use {@link tryAsync}.
9794
*
98-
* ### Naming convention
95+
* ## Naming convention
9996
*
10097
* - **Result with a value:** name it after the value (`user`, `config`)
10198
* - **Result without a value:** use `result`
@@ -132,7 +129,7 @@ import type { Task } from "./Task.js";
132129
* };
133130
* ```
134131
*
135-
* ### Combining multiple error types
132+
* ## Combining errors
136133
*
137134
* ```ts
138135
* const example = (value: string): Result<number, FooError | BarError> => {
@@ -146,7 +143,7 @@ import type { Task } from "./Task.js";
146143
* };
147144
* ```
148145
*
149-
* ### Unrecoverable errors
146+
* ## Unrecoverable errors
150147
*
151148
* Some errors can't be handled locally — they must propagate to the top level.
152149
* These are **unrecoverable errors**: expected (you know they can happen) but
@@ -187,7 +184,7 @@ import type { Task } from "./Task.js";
187184
* };
188185
* ```
189186
*
190-
* ### Unexpected errors
187+
* ## Unexpected errors
191188
*
192189
* Wrapping all unsafe code with {@link trySync} or {@link tryAsync} doesn't
193190
* prevent all errors — bugs can still throw. Catch them with global handlers:
@@ -201,16 +198,16 @@ import type { Task } from "./Task.js";
201198
*
202199
* TODO: Window and Node.js
203200
*
204-
* ### FAQ
201+
* ## FAQ
205202
*
206-
* #### What if my function doesn't return a value on success?
203+
* ### What if my function doesn't return a value on success?
207204
*
208205
* If your function performs an operation but doesn't need to return a value on
209206
* success, you can use `Result<void, E>`. Using `Result<void, E>` is clearer
210207
* than using `Result<true, E>` or `Result<null, E>` because it communicates
211208
* that the function doesn't produce a value but can produce errors.
212209
*
213-
* #### How do I process an array and stop on the first error?
210+
* ### How do I process an array and stop on the first error?
214211
*
215212
* ```ts
216213
* for (const item of items) {
@@ -219,7 +216,7 @@ import type { Task } from "./Task.js";
219216
* }
220217
* ```
221218
*
222-
* #### How do I process lazy operations?
219+
* ### How do I process lazy operations?
223220
*
224221
* When operations are represented as functions ({@link Lazy}), call each one and
225222
* check the result:
@@ -260,7 +257,7 @@ export interface Ok<T> {
260257
* The `error` property can be any type that describes the error. For domain
261258
* errors, use a plain object with a `type` field for discrimination.
262259
*
263-
* ### Example
260+
* ## Example
264261
*
265262
* ```ts
266263
* interface NotFoundError {
@@ -299,11 +296,11 @@ export type InferErr<R extends Result<any, any>> =
299296
/**
300297
* Creates an {@link Ok} result.
301298
*
302-
* - `ok()` creates an `Ok<void>` for operations that succeed without producing a
303-
* value.
304-
* - `ok(value)` creates an `Ok<T>` containing the specified value.
299+
* - `ok()` creates a `Result<void, never>` for operations that succeed without
300+
* producing a value.
301+
* - `ok(value)` creates a `Result<T, never>` containing the specified value.
305302
*
306-
* ### Example
303+
* ## Example
307304
*
308305
* ```ts
309306
* const noValue = ok();
@@ -313,15 +310,15 @@ export type InferErr<R extends Result<any, any>> =
313310
* console.log(success); // { ok: true, value: 42 }
314311
* ```
315312
*/
316-
export function ok(): Ok<void>;
313+
export function ok(): Result<void, never>;
317314
/** Creates an {@link Ok} result with a specified value. */
318-
export function ok<T>(value: T): Ok<T>;
319-
export function ok<T>(value = undefined): Ok<T> {
315+
export function ok<T>(value: T): Result<T, never>;
316+
export function ok<T>(value?: T): Result<T, never> {
320317
return { ok: true, value: value as T };
321318
}
322319

323320
/** Creates an {@link Err} result. */
324-
export const err = <E>(error: E): Err<E> => ({ ok: false, error });
321+
export const err = <E>(error: E): Result<never, E> => ({ ok: false, error });
325322

326323
/**
327324
* Extracts the value from a {@link Result} if it is an `Ok`, or throws an error
@@ -334,7 +331,7 @@ export const err = <E>(error: E): Err<E> => ({ ok: false, error });
334331
* - Not recommended for general error handling in application logic—prefer
335332
* explicit checks.
336333
*
337-
* ### Example
334+
* ## Example
338335
*
339336
* ```ts
340337
* // At app startup, crash if config is invalid:
@@ -362,7 +359,7 @@ export const getOrThrow = <T, E>(result: Result<T, E>): T => {
362359
* `T | null`.
363360
* - When the error is not important and you just want the value or nothing.
364361
*
365-
* ### Example
362+
* ## Example
366363
*
367364
* ```ts
368365
* // For APIs that expect T | null
@@ -375,7 +372,7 @@ export const getOrNull = <T, E>(result: Result<T, E>): T | null =>
375372
/**
376373
* Wraps a synchronous function that may throw, returning a {@link Result}.
377374
*
378-
* ### Example
375+
* ## Example
379376
*
380377
* ```ts
381378
* const parseJson = (value: string): Result<unknown, ParseJsonError> =>
@@ -399,7 +396,7 @@ export const trySync = <T, E>(
399396
/**
400397
* Wraps an async function that may throw, returning a {@link Result}.
401398
*
402-
* ### Example
399+
* ## Example
403400
*
404401
* ```ts
405402
* const fetchJson = (url: string): Promise<Result<unknown, FetchError>> =>

0 commit comments

Comments
 (0)