
Security News
Bun 1.2.19 Adds Isolated Installs for Better Monorepo Support
Bun 1.2.19 introduces isolated installs for smoother monorepo workflows, along with performance boosts, new tooling, and key compatibility fixes.
A functional, type-safe utility library for elegant error handling and asynchronous operations in JavaScript/TypeScript.
English | 한국어
Safe
is a functional utility library for JavaScript/TypeScript that simplifies error handling and asynchronous operations. It provides a fluent chainable API that makes your code more readable and maintainable while ensuring strong type safety.
Provides core functionality without the complexity of large libraries like
fp-ts
oreffect.ts
. Recognizing that most developers only use a fraction of what big libraries offer, Safe focuses on just the essentials with an intuitive API. All you need are the fundamental tools for type safety, error handling, and async operations.
unwrap()
or provide fallbacks with orElse()
npm install ts-safe
import { safe } from 'ts-safe';
const result = safe(10)
.map((x) => x * 2) // Transform the value (10 -> 20)
.ifOk(logValue) // Side effect with error propagation
.ifFail(handleErrors) // Error recovery if needed
.watch(observeState); // Side effect without error propagation
console.log(result.isOk); // Check if chain contains a success value
console.log(result.unwrap()); // Extract the final value (throws if there was an error)
import { safe } from 'ts-safe';
// Start with a value
const s1 = safe(100);
const s2 = safe(() => {
return 100;
});
const s3 = safe();
s1.unwrap() === s2.unwrap()
s3.unwarp() === undefined
// Example of transforming values in a chain
const result = safe(5)
.map((x) => x * 2) // 5 -> 10
.map((x) => x + 3) // 10 -> 13
.map((x) => `The value is ${x}`); // 13 -> "The value is 13"
console.log(result.isOk); // true
console.log(result.unwrap()); // "The value is 13"
// If there's an error, subsequent map operations are not executed
const errorResult = safe(1)
.map((x) => {
throw new Error('Error occurred');
})
.map((x) => x * 2); // This transformation is skipped due to the error
console.log(errorResult.isOk); // false
try {
errorResult.unwrap(); // Throws the error
} catch (e) {
console.error(e.message); // "Error occurred"
}
const promiseResult = safe(id)
.map(async (id)=>fetchData(id));
console.log(promiseResult.isOk); //Promise<boolean>
promiseResult.unwrap() // Promise<Data>
// Synchronous ifOk example - note that the return value doesn't change chain value
const syncResult = safe(42)
.ifOk((value) => {
console.log(`Processing value: ${value}`);
return Boolean(value); // This return value doesn't affect the chain's value
})
.unwrap(); // Still returns 42
// Asynchronous ifOk example - returning a Promise makes chain async
const asyncResult = safe('data')
.ifOk(async (data) => {
// The chain becomes asynchronous when a Promise is returned
await saveToDatabase(data);
console.log('Data saved successfully');
});
await asyncResult.isOk; // Promise<true>
const result = await asyncResult.unwrap(); // "data"
// ifOk with error propagation example
const errorResult = safe('data')
.ifOk((data) => {
throw new Error('Save Error'); // This error propagates through the chain
});
console.log(errorResult.isOk); // false
// errorResult.unwrap(); // Would throw 'Save Error'
// watch observes values and errors without affecting the chain
const result = safe(42)
.watch((result) => {
const {isOk,error,value} = result as SafeResult;
if (result.isOk) {
console.log(`Current value: ${result.value}`); // "Current value: 42"
} else {
console.error(`Error occurred: ${result.error.message}`);
}
// Errors thrown here don't affect the chain
throw new Error('This error is ignored!');
})
.map((x) => x * 2); // 42 -> 84
console.log(result.isOk); // true
console.log(result.unwrap()); // 84
// Returning a Promise in watch doesn't affect the chain's synchronicity
const syncChain = safe(10)
.watch(async (result) => {
if (result.isOk) {
await someAsyncOperation();
console.log('Async operation completed');
}
})
.map((x) => x + 5); // Chain remains synchronous
console.log(syncChain.unwrap()); // 15 (synchronous return)
// Error recovery example
const result = safe(() => {
throw new Error('Initial error');
})
.map((x) => x + 10) // Not executed due to the error
.ifFail((error) => {
console.log(`Error recovery: ${error.message}`);
return 42; // Provide a fallback value
})
.map((x) => x * 2); // Applied to the recovered value (42)
console.log(result.unwrap()); // 84
// fallback
const fallBackResult = safe(() => {
throw new Error('Async recovery needed');
});
console.log(fallBackResult.isOk); // false
console.log(fallBackResult.orElse(100)); // 100 no error
safe<T>(value: T): Safe<T>
safe<T>(fn: () => T): Safe<T>
safe(): Safe<undefined>
Wraps a value or function in a Safe. If a function is provided, it executes the function and stores the result in the Safe.
map<U>(transform: (value: T ) => U): Safe<T extends Promise<any> ? Promise<U> : U>
Transforms the value in the chain. Changes the value type from T to U.
watch(consumer: (result: SafeResult<T) => any): Safe<T>
Observes the current state of the chain without affecting it. Receives a result object containing either a value or an error.
ifOk<U>(effectFn: (value: T ) => U): Safe<U extends Promise<any> ? Promise<T> : T>
Conditionally applies a side effect ONLY when the Safe contains a success value (isOk = true). Completely skipped if the chain is in an error state. If it returns a Promise, the chain becomes asynchronous. Any errors thrown inside propagate to the chain.
ifFail<U>(handler: (error: Error) => U): Safe<T|U>
Conditionally executes the handler ONLY when the Safe contains an error (isOk = false). Provides a fallback or recovery value to continue the chain. Completely skipped if the chain is in a success state. If it returns a Promise, the chain becomes asynchronous.
isOk: Promise<boolean> | boolean
Property that indicates whether the chain contains a success value. Returns a Promise for asynchronous chains.
unwrap(): T
Extracts the final value from the chain. Throws an exception if the chain contains an error.
orElse<U>(fallbackValue: U): T | U
Extracts the value from the chain or returns the provided fallback value if there's an error. Unlike unwrap(), this method never throws an exception.
Safe intelligently handles synchronous and asynchronous operations according to these rules:
Methods without side effects (watch
)
Methods with side effects (ifOk
, ifFail
)
Value transformation methods (map
)
Safe comes with several powerful modules that extend its functionality:
Common validation and observer and retry patterns:
import { safe,errorIfNull, errorIfEmpty, watchOk, watchError,retry } from 'ts-safe';
safe(userData)
.ifOk(errorIfNull('User data is required')) // valid
.map((user) => user.email)
.ifOk(errorIfEmpty('Email cannot be empty'))
.ifOk(retry(sendMail)) // retry
.watch(watchOk(value => console.log(value))) // obserbe
.watch(watchError(error => console.error(error)));
Create reusable function pipelines that process data sequentially:
import { safe } from 'ts-safe';
const processNumber = safe.pipe(
(num: number) => num * 2,
(num: number) => num + 10,
(num: number) => `Result: ${num}`
);
console.log(processNumber(5).unwrap()); // "Result: 20"
MIT
FAQs
A functional, type-safe utility library for elegant error handling and asynchronous operations in JavaScript/TypeScript.
The npm package ts-safe receives a total of 990 weekly downloads. As such, ts-safe popularity was classified as not popular.
We found that ts-safe demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Bun 1.2.19 introduces isolated installs for smoother monorepo workflows, along with performance boosts, new tooling, and key compatibility fixes.
Security News
Popular npm packages like eslint-config-prettier were compromised after a phishing attack stole a maintainer’s token, spreading malicious updates.
Security News
/Research
A phishing attack targeted developers using a typosquatted npm domain (npnjs.com) to steal credentials via fake login pages - watch out for similar scams.