https://github.com/kolharsam/option-ts
option types for typescript
https://github.com/kolharsam/option-ts
option-type typescript
Last synced: 2 months ago
JSON representation
option types for typescript
- Host: GitHub
- URL: https://github.com/kolharsam/option-ts
- Owner: kolharsam
- License: mit
- Created: 2024-09-25T02:59:59.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2026-03-27T01:29:31.000Z (4 months ago)
- Last Synced: 2026-03-29T21:43:11.798Z (4 months ago)
- Topics: option-type, typescript
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/@kolharsam/option-ts
- Size: 330 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Security: SECURITY.md
Awesome Lists containing this project
README
[](https://deepwiki.com/kolharsam/option-ts)
[](https://github.com/kolharsam/option-ts/actions/workflows/node.js.yml)
# option-ts
This library provides Rust-inspired `Option` and `Result` types for TypeScript, enabling more robust error handling and null safety in your TypeScript projects.
## Installation
```bash
npm install @kolharsam/option-ts
```
## Usage
### Option
The `Option` type represents an optional value: every `Option` is either `Some` and contains a value, or `None`, and does not.
```typescript
import { Option, Some, None } from "@kolharsam/option-ts";
const someValue: Option = Some(5);
const noneValue: Option = None();
console.log(someValue.isSome()); // true
console.log(noneValue.isNone()); // true
// Transform values safely
const doubled = someValue.map((x) => x * 2);
console.log(doubled.get()); // 10
// Safe division function
const safeDiv = (a: number, b: number): Option => {
if (b === 0) return None();
return Some(a / b);
};
console.log(safeDiv(10, 2).getOrElse(0)); // 5
console.log(safeDiv(10, 0).getOrElse(0)); // 0
```
#### Pattern Matching with `match`
Use `match` for elegant pattern matching on Option values:
```typescript
const result = someValue.match({
Some: (value) => `Got value: ${value}`,
None: () => "No value found",
});
// Real-world example: User greeting
const user = Some({ name: "Alice", age: 30 });
const greeting = user.match({
Some: (u) => `Hello, ${u.name}! You are ${u.age} years old.`,
None: () => "Hello, guest!",
});
console.log(greeting); // "Hello, Alice! You are 30 years old."
```
### Result
The `Result` type represents either success (`Ok`) or failure (`Err`). It's useful for functions that can fail.
```typescript
import { Result, Ok, Err } from "@kolharsam/option-ts";
const okResult: Result = Ok(5);
const errResult: Result = Err("An error occurred");
console.log(okResult.isOk()); // true
console.log(errResult.isErr()); // true
// Transform success values while preserving errors
const doubled = okResult.map((x) => x * 2);
console.log(doubled.toOk().get()); // 10
// Safe division with detailed error handling
const safeDiv = (a: number, b: number): Result => {
if (b === 0) return Err("Division by zero");
return Ok(a / b);
};
console.log(safeDiv(10, 2).unwrapOr(0)); // 5
console.log(safeDiv(10, 0).unwrapOr(0)); // 0
```
#### Pattern Matching with `match`
Use `match` for comprehensive error handling:
```typescript
const handleResult = (input: string): string => {
const parseNumber = (str: string): Result => {
const num = parseInt(str, 10);
return isNaN(num) ? Err("Not a number") : Ok(num);
};
return parseNumber(input).match({
Ok: (num) => `The number is ${num}, squared: ${num * num}`,
Err: (error) => `Error: ${error}`,
});
};
console.log(handleResult("5")); // "The number is 5, squared: 25"
console.log(handleResult("abc")); // "Error: Not a number"
// API response handling
interface ApiResponse {
data: string[];
status: number;
}
const processApiResponse = (result: Result) => {
return result.match({
Ok: (response) => response.data.map((item) => item.toUpperCase()),
Err: (error) => [`Error: ${error}`],
});
};
```
## API Reference
### Option
- `Some(value: T): Option`
- `None(): Option`
- `get(): T`
- `getOrElse(defaultValue: T): T`
- `map(fn: (val: T) => U): Option`
- `inspect(fn: (val: T) => void): Option`
- `isSome(): boolean`
- `isNone(): boolean`
- `isSomeAnd(fn: (val: T) => boolean): boolean`
- `isNoneOr(fn: (val: T) => boolean): boolean`
- `asSlice(): T[] | []`
- `expect(msg: string): T`
- `unwrap(): T`
- `unwrapOr(def: T): T`
- `unwrapOrElse(fn: () => T): T`
- `mapOr(def: U, fn: (val: T) => U): U`
- `mapOrElse(def: () => U, fn: (val: T) => U): U`
- `okOr(err: E): Result`
- `okOrElse(fn: () => E): Result`
- `and(optionB: Option): Option`
- `andThen(fn: (val: T) => Option): Option`
- `or(optionB: Option): Option`
- `orElse(optFn: () => Option): Option`
- `xor(optionB: Option): Option`
- `zip(other: Option): Option<[T, U]>`
- `zipWith(other: Option, fn: (current: T, other: U) => V): Option`
- `match(patterns: { Some: (value: T) => U; None: () => U }): U`
### Result
- `Ok(value: T): Result`
- `Err(error: E): Result`
- `isOk(): boolean`
- `isOkAnd(fn: (val: T) => boolean): boolean`
- `isErr(): boolean`
- `isErrAnd(fn: (val: E) => boolean): boolean`
- `toOk(): Option`
- `toErr(): Option`
- `inspect(fn: (val: T) => void): Result`
- `inspectErr(fn: (val: E) => void): Result`
- `map(f: (val: T) => V): Result`
- `mapOr(def: V, f: (val: T) => V): V`
- `mapErr(fn: (err: E) => F): Result`
- `expect(msg: string): T`
- `unwrap(): T`
- `unwrapOrDefault(def: T): T`
- `expectErr(msg: string): E`
- `unwrapErr(): E`
- `and(res: Result): Result`
- `andThen(op: (val: T) => Result): Result`
- `or(res: Result): Result`
- `orElse(op: (err: E) => Result): Result`
- `unwrapOr(def: T): T`
- `unwrapOrElse(op: (err: E) => T): T`
- `match(patterns: { Ok: (value: T) => V; Err: (error: E) => V }): V`
### Utility Functions
- `unzip(option: Option<[T, U]>): [Option, Option]`
- `transpose(option: Option>): Result, E>`
- `flatten(option: Option>): Option`
- `transposeResult(res: Result, E>): Option>`
- `flattenResult(res: Result, E>): Result`
## Advanced Usage
### Chaining Operations
Both `Option` and `Result` support method chaining for elegant composition:
```typescript
// Option chaining
const user = Some({ name: "Alice", scores: [85, 92, 78] });
const result = user
.map((u) => u.scores)
.map((scores) => scores.reduce((a, b) => a + b, 0) / scores.length)
.map((avg) => Math.round(avg))
.match({
Some: (avg) => `Average score: ${avg}`,
None: () => "No scores available",
});
// Result chaining with error handling
const processUserData = (input: string) =>
parseJson(input)
.andThen(validateUser)
.andThen(calculateMetrics)
.match({
Ok: (metrics) => `Success: ${JSON.stringify(metrics)}`,
Err: (error) => `Failed: ${error}`,
});
```
### Working with Collections
Transform arrays safely using Option and Result:
```typescript
// Find first even number
const numbers = [1, 3, 5, 8, 9];
const firstEven = numbers.find((n) => n % 2 === 0)
? Some(numbers.find((n) => n % 2 === 0)!)
: None();
firstEven.match({
Some: (num) => console.log(`First even: ${num}`),
None: () => console.log("No even numbers found"),
});
// Process array with potential failures
const safeParseNumbers = (strings: string[]): Result => {
const results = strings.map((s) => {
const num = parseInt(s, 10);
return isNaN(num) ? Err(`Invalid: ${s}`) : Ok(num);
});
const failures = results.filter((r) => r.isErr());
if (failures.length > 0) {
return Err(
`Parse errors: ${failures.map((f) => f.unwrapErr()).join(", ")}`
);
}
return Ok(results.map((r) => r.unwrap()));
};
```
### Integration with Async/Await
Combine with promises for robust async error handling:
```typescript
async function fetchUser(id: string): Promise> {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
return Err(`HTTP ${response.status}: ${response.statusText}`);
}
const user = await response.json();
return Ok(user);
} catch (error) {
return Err(`Network error: ${error.message}`);
}
}
// Usage
const result = await fetchUser("123");
const message = result.match({
Ok: (user) => `Welcome, ${user.name}!`,
Err: (error) => `Login failed: ${error}`,
});
```
## Best Practices
1. **Prefer `match` for complex logic**: Use `match` when you need to handle both cases with different logic.
2. **Use specific error types**: Instead of generic strings, consider using custom error types for better type safety.
3. **Chain operations**: Take advantage of method chaining for readable data transformations.
4. **Avoid unwrap() in production**: Use `unwrapOr()`, `unwrapOrElse()`, or `match` for safer error handling.
5. **Combine with TypeScript**: Leverage TypeScript's type system for even better safety:
```typescript
type ApiError = "NetworkError" | "AuthError" | "ValidationError";
function apiCall(): Result {
// Implementation
}
// TypeScript will ensure all error cases are handled
apiCall().match({
Ok: (data) => processData(data),
Err: (error) => {
switch (error) {
case "NetworkError":
return retryRequest();
case "AuthError":
return redirectToLogin();
case "ValidationError":
return showValidationErrors();
}
},
});
```
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
This project is licensed under the MIT License.