npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

typescript-monads

v9.5.0

Published

Write cleaner TypeScript

Downloads

3,202

Readme

typescript-monads helps you write safer code by using abstractions over messy control flow and state.

Installation

You can use this library in the browser, node, or a bundler

Node or as a module

npm install typescript-monads

Browser

<head>
 <script src="https://unpkg.com/typescript-monads"></script>
 <!-- or use a specific version to avoid a http redirect --> 
 <script src="https://unpkg.com/[email protected]/index.min.js"></script>
</head>
var someRemoteValue;
typescriptMonads.maybe(someRemoteValue).tapSome(console.log)

Example Usage

Maybe

The Maybe monad represents values that may or may not exist. It's a safe way to handle potentially null or undefined values without resorting to null checks throughout your code.

import { maybe, none } from 'typescript-monads'

// Creating Maybe instances
const someValue = maybe(42)        // Maybe with a value
const noValue = maybe(null)        // Maybe with no value (None)
const alsoNoValue = none<number>() // Explicitly create a None

// Safe value access
someValue.valueOr(0)           // 42
noValue.valueOr(0)             // 0
someValue.valueOrCompute(() => expensiveCalculation()) // 42 (computation skipped)
noValue.valueOrCompute(() => expensiveCalculation())   // result of computation

// Conditional execution with pattern matching
someValue.match({
  some: val => console.log(`Got a value: ${val}`),
  none: () => console.log('No value present')
}) // logs: "Got a value: 42"

// Side effects with tap
someValue.tap({
  some: val => console.log(`Got ${val}`),
  none: () => console.log('Nothing to see')
})

// Conditional side effects
someValue.tapSome(val => console.log(`Got ${val}`))
noValue.tapNone(() => console.log('Nothing here'))

// Chaining operations (only executed for Some values)
maybe(5)
  .map(n => n * 2)           // maybe(10)
  .filter(n => n > 5)        // maybe(10)
  .flatMap(n => maybe(n + 1)) // maybe(11)

// Transforming to other types
maybe(5).toResult('No value found') // Ok(5)
maybe(null).toResult('No value found') // Fail('No value found')

// Working with RxJS (with rxjs optional dependency)
import { maybeToObservable } from 'typescript-monads'
maybeToObservable(maybe(5)) // Observable that emits 5 and completes
maybeToObservable(none())   // Observable that completes without emitting

List

The List monad is a lazily evaluated collection with chainable operations. It provides many of the common list processing operations found in functional programming languages.

import { List } from 'typescript-monads'

// Creating Lists
const fromValues = List.of(1, 2, 3, 4, 5)
const fromIterable = List.from([1, 2, 3, 4, 5])
const numbersFromRange = List.range(1, 10)    // 1 to 10
const infiniteNumbers = List.integers()        // All integers (use with take!)
const empty = List.empty<number>()

// Basic operations
fromValues.toArray() // [1, 2, 3, 4, 5]
fromValues.headOrUndefined() // 1
fromValues.headOr(0) // 1
empty.headOr(0) // 0

// Transformations
fromValues
  .map(n => n * 2)                 // [2, 4, 6, 8, 10]
  .filter(n => n > 5)              // [6, 8, 10]
  .take(2)                         // [6, 8]
  .drop(1)                         // [8]

// LINQ-style operations
fromValues.sum()                    // 15
fromValues.all(n => n > 0)          // true
fromValues.any(n => n % 2 === 0)    // true
fromValues.where(n => n % 2 === 0)  // [2, 4]

// Conversion
fromValues.toDictionary()           // { 0: 1, 1: 2, 2: 3, 3: 4, 4: 5 }
const users = List.of(
  { id: 'a', name: 'Alice' },
  { id: 'b', name: 'Bob' }
)
users.toDictionary('id') // { 'a': { id: 'a', name: 'Alice' }, 'b': { id: 'b', name: 'Bob' } }

Either

The Either monad represents values that can be one of two possible types. It's often used to represent a value that can be either a success (Right) or a failure (Left).

import { either } from 'typescript-monads'

// Creating Either instances
const rightValue = either<string, number>(undefined, 42) // Right value
const leftValue = either<string, number>('error', undefined) // Left value

// Checking which side is present
rightValue.isRight() // true
rightValue.isLeft()  // false
leftValue.isRight()  // false 
leftValue.isLeft()   // true

// Pattern matching
rightValue.match({
  right: val => `Success: ${val}`,
  left: err => `Error: ${err}`
}) // "Success: 42"

// Side effects with tap
rightValue.tap({
  right: val => console.log(`Got right: ${val}`),
  left: err => console.log(`Got left: ${err}`)
})

// Transformation (only applies to Right values)
rightValue.map(n => n * 2) // Either with Right(84)
leftValue.map(n => n * 2)  // Either with Left('error') unchanged

// Chaining (flatMap only applies to Right values)
rightValue.flatMap(n => either(undefined, n + 10)) // Either with Right(52)
leftValue.flatMap(n => either(undefined, n + 10))  // Either with Left('error') unchanged

Reader

The Reader monad represents a computation that depends on some external configuration or environment. It's useful for dependency injection.

import { reader } from 'typescript-monads'

// Define a configuration type
interface Config {
  apiUrl: string
  apiKey: string
}

// Create readers that depend on this configuration
const getApiUrl = reader<Config, string>(config => config.apiUrl)
const getApiKey = reader<Config, string>(config => config.apiKey)

// Compose readers to build more complex operations
const getAuthHeader = getApiKey.map(key => `Bearer ${key}`)

// Create a reader for making an API request
const fetchData = reader<Config, Promise<Response>>(config => {
  return fetch(`${config.apiUrl}/data`, {
    headers: {
      'Authorization': `Bearer ${config.apiKey}`
    }
  })
})

// Execute the reader with a specific configuration
const config: Config = {
  apiUrl: 'https://api.example.com',
  apiKey: 'secret-key-123'
}

const apiUrl = getApiUrl.run(config)  // 'https://api.example.com'
const authHeader = getAuthHeader.run(config) // 'Bearer secret-key-123'
fetchData.run(config).then(response => {
  // Handle API response
})

Result

The Result monad represents operations that can either succeed with a value or fail with an error. It's similar to Either but with more specific semantics for success/failure.

import { ok, fail, catchResult } from 'typescript-monads'

// Creating Result instances
const success = ok<number, string>(42)        // Success with value 42
const failure = fail<number, string>('error') // Failure with error 'error'

// Safely catching exceptions
const result = catchResult<number, Error>(
  () => {
    // Code that might throw
    if (Math.random() > 0.5) {
      throw new Error('Failed')
    }
    return 42
  }
)

// Checking result type
success.isOk()   // true
success.isFail() // false
failure.isOk()   // false
failure.isFail() // true

// Extracting values safely
success.unwrapOr(0)   // 42
failure.unwrapOr(0)   // 0
success.unwrap()      // 42
// failure.unwrap()   // Throws error

// Convert to Maybe
success.maybeOk()    // Maybe with Some(42)
failure.maybeOk()    // Maybe with None
success.maybeFail()  // Maybe with None
failure.maybeFail()  // Maybe with Some('error')

// Pattern matching
success.match({
  ok: val => `Success: ${val}`,
  fail: err => `Error: ${err}`
}) // "Success: 42"

// Transformations
success.map(n => n * 2)          // Ok(84)
failure.map(n => n * 2)          // Fail('error') unchanged
failure.mapFail(e => `${e}!`)    // Fail('error!') 

// Chaining
success.flatMap(n => ok(n + 10)) // Ok(52)
failure.flatMap(n => ok(n + 10)) // Fail('error') unchanged

// Side effects
success.tap({
  ok: val => console.log(`Success: ${val}`),
  fail: err => console.log(`Error: ${err}`)
})
success.tapOk(val => console.log(`Success: ${val}`))
failure.tapFail(err => console.log(`Error: ${err}`))

// Chaining with side effects
success
  .tapOkThru(val => console.log(`Success: ${val}`))
  .map(n => n * 2)

// Converting to promises
import { resultToPromise } from 'typescript-monads'
resultToPromise(success) // Promise that resolves to 42
resultToPromise(failure) // Promise that rejects with 'error'

State

The State monad represents computations that can read and transform state. It's useful for threading state through a series of operations.

import { state } from 'typescript-monads'

// Define a state type
interface AppState {
  count: number
  name: string
}

// Initial state
const initialState: AppState = {
  count: 0,
  name: ''
}

// Create operations that work with the state
const incrementCount = state<AppState, number>(s => 
  [{ ...s, count: s.count + 1 }, s.count + 1]
)

const setName = (name: string) => state<AppState, void>(s => 
  [{ ...s, name }, undefined]
)

const getCount = state<AppState, number>(s => [s, s.count])

// Compose operations
const operation = incrementCount
  .flatMap(() => setName('Alice'))
  .flatMap(() => getCount)

// Run the state operation
const result = operation.run(initialState)
console.log(result.state)  // { count: 1, name: 'Alice' }
console.log(result.value)  // 1

Logger

The Logger monad lets you collect logs during a computation. It's useful for debugging or creating audit trails.

import { logger, tell } from 'typescript-monads'

// Create a logger with initial logs and value
const initialLogger = logger<string, number>(['Starting process'], 0)

// Add logs and transform value
const result = initialLogger
  .flatMap(val => {
    return logger(['Incrementing value'], val + 1)
  })
  .flatMap(val => {
    return logger(['Doubling value'], val * 2)
  })

// Extract all logs and final value
result.runUsing(({ logs, value }) => {
  console.log('Logs:', logs)    // ['Starting process', 'Incrementing value', 'Doubling value']
  console.log('Final value:', value) // 2
})

// Start with a single log entry
const startLogger = tell<string>('Beginning')

// Add a value to the logger
const withValue = logger.startWith<string, number>('Starting with value:', 42)

// Extract results using pattern matching
const output = result.runUsing(({ logs, value }) => {
  return { 
    history: logs.join('\n'),
    result: value 
  }
})

Integration with Other Libraries

RxJS Integration

This library offers RxJS integration with the Maybe and Result monads:

import { maybeToObservable } from 'typescript-monads'
import { resultToObservable } from 'typescript-monads'
import { of } from 'rxjs'
import { flatMap } from 'rxjs/operators'

// Convert Maybe to Observable
of(maybe(5)).pipe(
  flatMap(maybeToObservable)
).subscribe(val => console.log(val)) // logs 5 and completes

// Convert Result to Observable  
of(ok(42)).pipe(
  flatMap(resultToObservable)
).subscribe(
  val => console.log(`Success: ${val}`),
  err => console.error(`Error: ${err}`)
)

Promise Integration

You can convert Result monads to promises:

import { resultToPromise } from 'typescript-monads'

// Convert Result to Promise
resultToPromise(ok(42))
  .then(val => console.log(`Success: ${val}`))
  .catch(err => console.error(`Error: ${err}`))

// Catch exceptions and convert to Result
async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data')
    if (!response.ok) {
      throw new Error(`HTTP error ${response.status}`)
    }
    return ok(await response.json())
  } catch (error) {
    return fail(error)
  }
}

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT