1.0.1 • Published 9 months ago
neverthrow-safe-ret v1.0.1
neverthrow-safe-ret
Type-safe error handling with Go-style tuple returns for neverthrow
This library extends neverthrow to provide a Go-inspired error-handling pattern while maintaining strict type safety. If you’ve ever wanted to destructure a Result into a [error, value] tuple without losing type information, this is for you.
Features
- Go-style tuple returns: Use 
[err, value]destructuring with type inference. - Zero dependencies: Works alongside 
neverthrow, no bloat. - Monkey-patch integration: Add 
.safeRet()directly toResultinstances. - Type enforcement: Forces error checks at compile time via 
undefinednarrowing. - Seamless interop: Works with existing 
neverthrowcode. 
Installation
npm install neverthrow-safe-ret  Why?
The original neverthrow issue #614 highlights the friction of chaining .andThen() for sequential operations. This library solves it by:
- Letting you exit early on errors without callback hell.
 - Inferring types after checks (e.g., 
valuebecomes non-undefinedpost-error guard). 
Usage
Basic Example
import { ok, err } from 'neverthrow';  
import 'neverthrow-safe-ret';  
const result = ok(42).safeRet();  
const [error, value] = result;  
if (error) {  
  // Handle error (type: Error | undefined)  
} else {  
  console.log(value); // Type: number  
}  Real-World Chain
import { Result, ok, err } from 'neverthrow';  
import 'neverthrow-safe-ret';  
declare function getUser(id: string): Result<User, Error>;  
declare function validate(user: User): Result<boolean, ValidationError>;  
function processUser(id: string): Result<boolean, Error | ValidationError> {  
  const [fetchErr, user] = getUser(id).safeRet();  
  if (fetchErr) return err(fetchErr);  
  const [validationErr, isValid] = validate(user).safeRet();  
  if (validationErr) return err(validationErr);  
  return ok(isValid);  
}  How It Works
The .safeRet() method returns a tuple where:
- Error position: 
E(undefined ifOk). - Value position: 
T(undefined ifErr). 
Type narrowing example:
const [e, s] = ok("string").safeRet();
// e: undefined, s: string
const [e2, s2] = err("error").safeRet();
// e2: "error", s2: undefined
function a(x: Result<number, string>): Result<number, string> {
  const [e3, s3] = x.safeRet();
  // e3: string | undefined, s3: number | undefined
  // this forces you to check for e3
  if (typeof e3 !== "undefined") {
    // here we are sure that e3 is string and s3 is undefined
    return err(e3);
  }
  // s3 is now number
  return ok(s3);
}Comparison
| Approach | Code Style | Type Safety | Error Checks Enforced | 
|---|---|---|---|
Vanilla neverthrow | Method chaining | ✅ | ❌ (via match) | 
neverthrow-safe-ret | Imperative checks | ✅ | ✅ (via undefined) | 
Caveats
- Monkey-patching: Modifies 
Resultprototypes. Avoid if your team dislikes patching. 
Contributing
PRs welcome!
Credit: Inspired by neverthrow#614. License: MIT