What is Dark Matter?

The substrate within which the entire universe expands, but also our utility library

Dark matter is a TypeScript library for handling success and failure cases in a type-safe way. It provides a Result type system and utilities for working with Results, including type guards, creation functions, and composition utilities.

Installation

deno add @joyautomation/dark-matter

Usage

Creating Results

Use createSuccess and createFail to create Result objects:

import { createSuccess, createFail } from "@joyautomation/dark-matter";

// Create a success result
const success = createSuccess(42);
// Type: ResultSuccess<number>
// Value: { success: true, output: 42 }

// Create a failure result
const failure = createFail("Something went wrong");
// Type: ResultFail
// Value: { success: false, error: "Something went wrong" }

Type Guards

Use isSuccess and isFail to check the type of a Result:

import { isSuccess, isFail } from "@joyautomation/dark-matter";

const result = createSuccess(42);

if (isSuccess(result)) {
  // TypeScript knows result.output is a number
  console.log(result.output * 2); // 84
}

if (isFail(result)) {
  // TypeScript knows result.error exists
  console.log(result.error);
}

Unwrapping Results

Use unwrapResults to safely extract values from an array of Results:

import { unwrapResults } from "@joyautomation/dark-matter";

const results = [
  createSuccess(1),
  createSuccess("hello"),
  createSuccess({ key: "value" })
] as const;

// Unwrap all results at once
const [num, str, obj] = unwrapResults(results);
// num: 1
// str: "hello"
// obj: { key: "value" }

// Throws if any result is a failure
try {
  unwrapResults([createSuccess(1), createFail("error")]);
} catch (e) {
  console.error(e); // "Cannot unwrap failed result: error"
}

Piping Functions

Use resultPipe to compose functions that return Results:

import { resultPipe } from "@joyautomation/dark-matter";

const addOne = (n: number) => createSuccess(n + 1);
const double = (n: number) => createSuccess(n * 2);
const validatePositive = (n: number) =>
  n > 0 ? createSuccess(n) : createFail("Number must be positive");

// Pipe synchronous functions
const result1 = await resultPipe(
  () => createSuccess(5),
  addOne,
  double
); // Success(12)

// Pipe async functions
const result2 = await resultPipe(
  async () => createSuccess(1),
  async (n) => createSuccess(n + 1),
  validatePositive
); // Success(2)

// Early failure
const result3 = await resultPipe(
  () => createSuccess(-1),
  validatePositive, // Fails here
  double // Never executed
); // Fail("Number must be positive")

Working with Collections

Use allSuccess to check if all Results in a collection are successful:

import { allSuccess } from "@joyautomation/dark-matter";

const results = [
  createSuccess(1),
  createSuccess("test")
] as const;

if (allSuccess(results)) {
  // TypeScript knows results is [ResultSuccess<1>, ResultSuccess<"test">]
  const [num, str] = results.map(r => r.output);
  console.log(num, str); // 1, "test"
}

// Works with any number of results
const mixed = [createSuccess(1), createFail("error"), createSuccess(3)];
console.log(allSuccess(mixed)); // false

JSR NPM Github