Skip to main content Link Search Menu Expand Document (external link)

NonNullableX overview

Helpers for working with non-nullable values.

Added in v0.0.0


Table of contents


mapping

lift

Lifts a total function (a: A) => B into one that tolerates nullish input, applying it to present values and passing null/undefined through unchanged.

Where map operates on a value, lift transforms the function itself, yielding a reusable (a: A | null | undefined) => B | null | undefined you can drop into a pipe. Use it to adapt a plain transform to a nullable pipeline without wrapping each call site.

Signature

export declare const lift: <A, B>(map: (a: A) => B) => (a: A | null | undefined) => B | null | undefined

Example

import { NonNullableX } from "@nunofyobiz/effect-extras"
import { Number, pipe } from "effect"

const addOne = NonNullableX.lift(Number.sum(1))

assert.deepStrictEqual(pipe(1, addOne), 2)
assert.deepStrictEqual(pipe(null, addOne), null)
assert.deepStrictEqual(pipe(undefined, addOne), undefined)

Added in v0.0.0

map

Applies map to a only when it is non-nullish, passing nullish inputs through unchanged.

This is the nullable-preserving map: a present value is transformed to B, while null stays null and undefined stays undefined, so nullability is carried through the transformation. Supports both data-first and data-last (pipeable) call styles.

Signature

export declare const map: (<A, B>(map: (a: NonNullable<A>) => B) => (a: A) => B | (null & A) | (undefined & A)) &
  (<A, B>(a: A, map: (a: NonNullable<A>) => B) => B | (null & A) | (undefined & A))

Example

import { NonNullableX } from "@nunofyobiz/effect-extras"
import { pipe } from "effect"

// Data-first — present value is transformed
assert.deepStrictEqual(
  NonNullableX.map(1, (v: number) => v + 1),
  2
)

// Data-last — nullish passes through unchanged
const value: number | null = null
assert.deepStrictEqual(
  pipe(
    value,
    NonNullableX.map<number | null, number>((v) => v + 1)
  ),
  null
)

Added in v0.0.0

ordering

nullableOrder

Extends an Order.Order<A> to an Order.Order<A | null>, deciding where null sorts relative to present values via the behavior argument.

Pass "value-null" to push nulls to the end and "null-value" to pull them to the front; two present values fall back to the wrapped order. Use it to sort collections that mix real values with gaps without a bespoke comparator. Supports both data-first and data-last (pipeable) call styles.

Signature

export declare const nullableOrder: ((
  behavior: "value-null" | "null-value"
) => <A>(order: Order.Order<A>) => Order.Order<A | null>) &
  (<A>(order: Order.Order<A>, behavior: "value-null" | "null-value") => Order.Order<A | null>)

Example

import { NonNullableX } from "@nunofyobiz/effect-extras"
import { Array, Order, pipe } from "effect"

// "value-null" — nulls sorted last
assert.deepStrictEqual(
  pipe([null, 1, 3, null, 2], Array.sort(NonNullableX.nullableOrder(Order.Number, "value-null"))),
  [1, 2, 3, null, null]
)

// "null-value" — nulls sorted first (data-last)
assert.deepStrictEqual(
  pipe([null, 1, 3, null, 2], Array.sort(pipe(Order.Number, NonNullableX.nullableOrder("null-value")))),
  [null, null, 1, 2, 3]
)

Added in v0.0.0

pattern matching

match

Branches on whether value is nullish, passing the value narrowed to NonNullable<A> to the whenNotNullable handler.

A nullable-aware sibling of Match.value: it folds a present-or-absent value into a single B without an if/else or a manual != null check. Note that falsy-but-present values ("", 0, false) take the whenNotNullable branch — only null and undefined are treated as absent. Supports both data-first and data-last (pipeable) call styles.

Signature

export declare const match: (<A, B>(handlers: {
  whenNullable: () => B
  whenNotNullable: (value: NonNullable<A>) => B
}) => (value: A) => B) &
  (<A, B>(value: A, handlers: { whenNullable: () => B; whenNotNullable: (value: NonNullable<A>) => B }) => B)

Example

import { NonNullableX } from "@nunofyobiz/effect-extras"
import { pipe } from "effect"

// Data-first — present value flows through narrowed
assert.deepStrictEqual(
  NonNullableX.match("value", {
    whenNullable: () => "nullable",
    whenNotNullable: (value) => value
  }),
  "value"
)

// Data-last — null takes the whenNullable branch
assert.deepStrictEqual(
  pipe(
    null,
    NonNullableX.match({
      whenNullable: () => "nullable",
      whenNotNullable: (value) => value
    })
  ),
  "nullable"
)

Added in v0.0.0

unsafe

fromNullableOrThrow

Returns value narrowed to NonNullable<A>, throwing an Error if it is null or undefined.

Use it at trusted boundaries where a value is known to be present but typed as nullable, turning a silent undefined into a loud failure. An optional variableName is woven into the thrown message to aid debugging. This is the function re-exported as nn from the module barrel, a terse shorthand handy inside string interpolations.

Signature

export declare const fromNullableOrThrow: <A>(value: A, variableName?: string) => NonNullable<A>

Example

import { NonNullableX } from "@nunofyobiz/effect-extras"

assert.deepStrictEqual(NonNullableX.fromNullableOrThrow("value"), "value")

assert.throws(
  () => NonNullableX.fromNullableOrThrow(null, "varName"),
  /Value is nullable: null \(variable name: varName\)/
)

Added in v0.0.0