
Security News
Insecure Agents Podcast: Certified Patches, Supply Chain Security, and AI Agents
Socket CEO Feross Aboukhadijeh joins Insecure Agents to discuss CVE remediation and why supply chain attacks require a different security approach.
Simple Maybe monad written in TypeScript

A Maybe represents a wrapper around any value - most commonly values that might be nullable. Having this wrapper is useful because it guards against null and undefined when doing computations on the value. The idea is that the Maybe deals with nullables internally, thus allowing one to write simpler code with fewer conditionals. Not until the very end when it's needed to unwrap the value again, is it necessary to deal with the fact that it was or somehow became nullable.
Maybe.fromNullable(getValueThatMightNotBeThere())
.map(doSomething)
.map(doAnotherThing)
.map(doFinalThing)
.getOrElse(defaultValue);
Even though they can't be constructed individually, the Maybe consists of two classes: Just and Nothing. The Maybe is a Just if it holds a value and a Nothing if it doesn't.
const toUpper = a => a.toUpperCase();
Maybe.fromNullable(['foo', 'bar', 'baz'][2]) // Just('baz')
.map(toUpper) // Just('BAZ')
.getOrElse('No value here');
// => 'BAZ'
Maybe.fromNullable(['foo', 'bar', 'baz'][3]) // Nothing
.map(toUpper) // Nothing
.getOrElse('No value here');
// => 'No value here'
There exists a number of great resources on Maybe monads - including The Marvellously Mysterious JavaScript Maybe Monad by @jrsinclair and Professor Frisby's Mostly Adequate Guide to Function Programming by @drboolean - that one might want to get familiar with. If you are used to Promises, you are essentially already familiar with monads.
kanskje stems from the need of a simple Maybe monad with type declarations making it usable for both JavaScript and TypeScript. The fact that the Maybe is written in TypeScript makes sure that it only contains methods that are actually possible to express using the TypeScript type system.
The source code is simple with one-line functions and no aliases, and yet the function declarations - using Generic Types of TypeScript - should be self-documenting.
Unlike some Maybe monads, kanskje doesn't perform behind the scenes conversions from Just to Nothing. As an example you can pass any mapper function, f: (a: A) => B, to map and be sure that the return type of f isn't checked. A Just is kept a Just even if f returns a nullable:
const unsafeProp = b => a => a[b];
Maybe.of({ name: 'Alice' }) // Just({ name: 'Alice' })
.map(unsafeProp('age')) // Just(undefined)
.getOrElse(25);
// => undefined
If Just(undefined) is not the desired outcome, the mapper function, f, needs to return a Maybe and be passed to chain instead:
const safeProp = b => a => Maybe.fromNullable(a[b]);
Maybe.of({ name: 'Alice' }) // Just({ name: 'Alice' })
.chain(safeProp('age')) // Nothing
.getOrElse(25);
// => 25
This is a CommonJS module.
Import the exported functions as named imports:
const { all, empty, fromNullable, of } = require('kanskje');
Or namespace them all under e.g. Maybe:
const Maybe = require('kanskje');
Or use ES2015 module syntax if your environment supports that:
import { all, empty, fromNullable, of } from 'kanskje';
import * as Maybe from 'kanskje';
MaybesTo construct a Maybe one of the following functions can be used:
allAccepts an array or a tuple of Maybes and returns a single Maybe. If all the Maybes were Justs, the resulting Maybe will be a Just containing their values. If any of the Maybes where a Nothing, the resulting Maybe will be a Nothing.
Signature:
all<A>(maybes: Maybe<A>[]): Maybe<A[]>
all<A, B>(maybes: [Maybe<A>, Maybe<B>]): Maybe<[A, B]>
all<A, B, C>(maybes: [Maybe<A>, Maybe<B>, Maybe<C>]): Maybe<[A, B, C]>
all<A, B, C, D>(
maybes: [Maybe<A>, Maybe<B>, Maybe<C>, Maybe<D>]
): Maybe<[A, B, C, D]>
all<A, B, C, D, E>(
maybes: [Maybe<A>, Maybe<B>, Maybe<C>, Maybe<D>, Maybe<E>]
): Maybe<[A, B, C, D, E]>
Example:
Maybe.all([Maybe.of('foo'), Maybe.of('bar'), Maybe.of('baz')]);
// => Just(['foo', 'bar', 'baz'])
Maybe.all([Maybe.of('foo'[1]), Maybe.of('bar'[3]), Maybe.of('baz'[2])]);
// => Just(['o', undefined, 'z'])
Maybe.all([
Maybe.of('foo'[1]),
Maybe.fromNullable('bar'[3]),
Maybe.of('baz'[2]),
]);
// => Nothing
emptyReturns a Nothing.
Signature:
empty<A>(): Maybe<A>
Example:
Maybe.empty();
// => Nothing
fromNullableLifts a value into a Maybe but checks if the value is either null or undefined. If that is a case, a Nothing is returned. Otherwise a Just is returned.
Signature:
fromNullable<A>(a: Nullable<A>): Maybe<A>
Example:
Maybe.fromNullable('foo');
// => Just('foo')
Maybe.fromNullable(['foo', 'bar', 'baz'][3]);
// => Nothing
ofLifts a value into a Maybe, more specifically: a Just.
Signature:
of<A>(a: A): Maybe<A>
Example:
Maybe.of('foo');
// => Just('foo')
Maybe.of(['foo', 'bar', 'baz'][3]);
// => Just(undefined)
Maybe methodsOnce a Maybe is constructed, the following methods are accessible on the instance:
chainAccepts a mapper function, f, that returns a Maybe and automatically unwraps the outer Maybe to not end up with a Maybe<Maybe<B>>.
Signature:
chain<B>(f: (a: A) => Maybe<B>): Maybe<B>
Example:
const safeHead = xs => Maybe.fromNullable(xs[0]);
Maybe.of([1, 2, 3]).chain(safeHead);
// => Just(1)
Maybe.of([]).chain(safeHead);
// => Nothing
filterAccepts a predicate function, f, and converts the Maybe from a Just to a Nothing if its value does not adhere. If the Maybe is already a Nothing it remains a Nothing.
Note: If used with TypeScript f can be a Type Guard.
Signature:
filter(f: (a: A) => boolean): Maybe<A>
filter<B extends A>(f: (a: A) => a is B): Maybe<B>
Examples:
Using a predicate function:
const isEven = a => a % 2 === 0;
Maybe.of(4).filter(isEven);
// => Just(4)
Maybe.of(7).filter(isEven);
// => Nothing
Using a TypeScript Type Guard:
interface Admin extends Person {
password: string;
}
interface Person {
name: string;
}
function isAdmin(a: Person): a is Admin {
return a.hasOwnProperty('password');
}
const carl: Admin = {
name: 'Carl',
password: '1234',
};
const persons: Person[] = [
{
name: 'Alice',
},
carl,
];
Maybe.fromNullable(persons[0]).filter(isAdmin);
// => Nothing
Maybe.fromNullable(persons[1]).filter(isAdmin);
// => Just({ name: 'Carl', password: '1234' })
foldAccepts two functions: a mapper function, f, and a function with the same return type, g. If the Maybe is a Just its value is mapped and returned using f. If it's a Nothing the result of g is returned.
Signature:
fold<B>(f: (a: A) => B, g: () => B): B
Example:
const unsafeProp = b => a => a[b];
const persons = [
{
name: 'Alice',
},
{
name: 'Bob',
},
];
Maybe.fromNullable(persons[1]).fold(
unsafeProp('name'),
() => 'A person does not exist',
);
// => 'Bob'
Maybe.fromNullable(persons[2]).fold(
unsafeProp('name'),
() => 'A person does not exist',
);
// => 'A person does not exist'
getOrElseAccepts a default value, a, and returns that if the Maybe is a Nothing. Otherwise the value of the Just is returned.
Signature:
getOrElse(a: A): A
Example:
Maybe.fromNullable(getPortFromProcess()).getOrElse(3000);
isJustReturns true if the Maybe is a Just and false if it's a Nothing.
Signature:
isJust(): boolean
isNothingReturns true if the Maybe is a Nothing and false if it's a Just.
Signature:
isNothing(): boolean
mapAccepts any mapper function, f, and applies it to the value of the Maybe. If f returns a Maybe, the result will be a nested Maybe.
Signature:
map<B>(f: (a: A) => B): Maybe<B>
Example:
const length = a => a.length;
Maybe.of('foo').map(length);
// => Just(3)
const safeHead = xs => Maybe.fromNullable(xs[0]);
Maybe.of([1, 2, 3]).map(safeHead);
// => Just(Just(1))
Maybe.of([]).map(safeHead);
// => Just(Nothing)
orElseAccepts a Maybe, a. If the instance Maybe is a Nothing it is replaced with a. Otherwise it is left unchanged.
Signature:
orElse(a: Maybe<A>): Maybe<A>
Example:
const persons = [
{
name: 'Alice',
},
{
name: 'Bob',
},
];
Maybe.fromNullable(persons[1]).orElse(Maybe.of({ name: 'Carl' }));
// => Just('Bob')
Maybe.fromNullable(persons[2]).orElse(Maybe.of({ name: 'Carl' }));
// => Just('Carl')
unsafeGetUnsafely unwraps the value from the Maybe. Since Nothings don't contain a value, the function will throw an error if the Maybe happened to be a Nothing.
Signature:
unsafeGet(): A | void
Example:
Maybe.fromNullable(5).unsafeGet();
// => 5
Maybe.of(undefined).unsafeGet();
// => undefined
Maybe.fromNullable(undefined).unsafeGet();
// => TypeError: A Nothing holds no value.
FAQs
Simple Maybe monad written in TypeScript
We found that kanskje demonstrated a not healthy version release cadence and project activity because the last version was released 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
Socket CEO Feross Aboukhadijeh joins Insecure Agents to discuss CVE remediation and why supply chain attacks require a different security approach.

Security News
Tailwind Labs laid off 75% of its engineering team after revenue dropped 80%, as LLMs redirect traffic away from documentation where developers discover paid products.

Security News
The planned feature introduces a review step before releases go live, following the Shai-Hulud attacks and a rocky migration off classic tokens that disrupted maintainer workflows.