New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@jordan-hall/typeguard

Package Overview
Dependencies
Maintainers
0
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@jordan-hall/typeguard

A TypeScript library providing type-safe handling of `Result` types, pattern matching, and robust error handling utilities. Designed to enhance code reliability and readability by leveraging TypeScript's powerful type system.

  • 0.1.0
  • latest
  • Source
  • npm
  • Socket score

Version published
Maintainers
0
Created
Source

@jordan-hall/typeguard

A TypeScript library providing type-safe handling of Result types, pattern matching, and robust error handling utilities. Designed to enhance code reliability and readability by leveraging TypeScript's powerful type system.

Table of Contents

  • Features
  • Installation
  • Usage
  • API Reference
  • Examples
  • Contributing
  • License

Features

  • Result Types: Simplify error handling by encapsulating success and error states.
  • Pattern Matching: Perform expressive and type-safe pattern matching on Result types.
  • Try/Catch Utilities: Advanced try/catch helpers for synchronous and asynchronous functions with type-safe error management.
  • Type Guards and Predicates: Enhance pattern matching with custom type guards and predicate functions.
  • Flexible Patterns: Supports literal, regex, predicate, object, array, and many patterns.

Installation (coming soon JSR)

You can install @jordan-hall/typeguard via Pacakage Json:


### Using Bun
bun install @jordan-hall/typeguard

### Using npm
npm install @jordan-hall/typeguard

### Using yarn
yarn add @jordan-hall/typeguard

### Using pnpm
pnpm install @jordan-hall/typeguard

You can also use JSR (preferred). For import symbol view on JSR website

### Using Deno
deno add jsr:@jordan-hall/@jordan-hall/typeguard

### Using NPM
npx jsr add @jordanhall/@jordan-hall/typeguard

Usage

Result Types

Result<T, E> represents either a successful computation Ok<T> or a failed computation Err<E>.

import { Ok, Err, Result } from '@jordan-hall/typeguard';

type User = { id: number; name: string };
type ValidationError = { field: string; message: string };

const success: Result<User, ValidationError> = Ok({ id: 1, name: "John Doe" });
const failure: Result<User, ValidationError> = Err({ field: "email", message: "Invalid email format" });

Pattern Matching

Perform pattern matching on Result types for expressive and type-safe error handling.

import { match, when, _, Result } from '@jordan-hall/typeguard';

function getUser(id: number): Result<User, ValidationError> {
  if (id === 0) return Err({ field: "id", message: "Invalid user ID" });
  return Ok({ id, name: "Alice" });
}

const result = getUser(1);

const message = match(result,
  { type: 'Ok', pattern: when(user => user.id > 0), handler: user => `User ID: ${user.id}, Name: ${user.name}` },
  { type: 'Err', pattern: _, handler: error => `Error in field ${error.field}: ${error.message}` }
);

console.log(message); // Output: User ID: 1, Name: Alice
Advanced Pattern Matching

Utilize type guards, predicates, and array patterns for complex matching scenarios.

import { match, when, guard, some, every, _ } from '@jordan-hall/typeguard';

interface Order {
  id: string;
  items: Array<{ name: string; price: number }>;
}

interface OrderError {
  code: string;
  message: string;
}

const processOrder = (order: Order): Result<Order, OrderError> => {
  if (order.items.length === 0) return Err({ code: "NO_ITEMS", message: "Order must contain at least one item" });
  return Ok(order);
};

const orderResult = processOrder({ id: "order123", items: [{ name: "Book", price: 10 }] });

const message = match(orderResult,
  { type: 'Ok', pattern: some(when(item => item.price > 5)), handler: order => `Order ${order.id} has expensive items` },
  { type: 'Err', pattern: { code: "NO_ITEMS" }, handler: error => `Order Error: ${error.message}` },
  { type: 'Ok', pattern: _, handler: order => `Order ${order.id} processed successfully` }
);

console.log(message); // Output: Order order123 has expensive items

Try/Catch Utilities

Simplify error handling with type-safe tryCatch and tryCatchAsync functions.

Synchronous tryCatch
import { tryCatch } from '@jordan-hall/typeguard/tryCatch';

const [error, result] = tryCatch(() => JSON.parse('{"key": "value"}'));

if (result)) {
  console.log("Parsed value:", result);
} else {
  console.error("Parsing error:", error);
}
Asynchronous tryCatchAsync
import { tryCatchAsyn } from '@jordan-hall/typeguard/tryCatch';

async function fetchData(): Promise<string> {
  // Simulate fetching data
  return "data";
}

const [error, data] = await tryCatchAsync(() => fetchData());

if (data) {
  console.log("Fetched data:", data);
} else {
  console.error("Fetching error:", error);
}

Utility Functions

Predicates and Guards

Create custom patterns using predicates and type guards.

import { when, guard, match, _, Result } from '@jordan-hall/typeguard';

interface Admin {
  role: 'admin';
  privileges: string[];
}

type User = { name: string; age: number } | Admin;

const isAdmin: guard<Admin> = (value): value is Admin => (value as Admin).role === 'admin';

const userResult: Result<User, string> = Ok({ name: "Bob", age: 25 });

const userMessage = match(userResult,
  { type: 'Ok', pattern: guard(isAdmin), handler: admin => `Admin with privileges: ${admin.privileges.join(", ")}` },
  { type: 'Ok', pattern: _, handler: user => `User: ${user.name}, Age: ${user.age}` },
  { type: 'Err', pattern: _, handler: error => `Error: ${error}` }
);

console.log(userMessage); // Output: User: Bob, Age: 25
Array Patterns

Match arrays with some or every patterns.

import { some, every, when, match, _ } from '@jordan-hall/typeguard';

type Data = number[];

const data: Data = [1, 2, 3, 4];

const pattern = some(when(n => n > 3));

const matchResult = match(data,
  { type: 'Ok', pattern: pattern, handler: () => "At least one number is greater than 3" },
  { type: 'Ok', pattern: _, handler: () => "No number is greater than 3" }
);

console.log(matchResult); // Output: At least one number is greater than 3

API Reference

Types

  • Result<T, E>
    Represents a computation that can either succeed with a value of type T or fail with an error of type E.

  • Ok<T, E>
    Represents a successful computation containing a value of type T.

  • Err<T, E>
    Represents a failed computation containing an error of type E.

Functions

Ok

Creates an Ok result.

const Ok = <T, E>(value: T): Result<T, E> => ({ _tag: 'Ok', value });
Err

Creates an Err result.

const Err = <T, E>(error: E): Result<T, E> => ({ _tag: 'Err', error });
match

Performs pattern matching on a Result type.

function match<T, E, R>(
  result: Result<T, E>,
  ...cases: Array<MatchCase<T, E, R>>
): R;
tryCatch

Executes a synchronous function with type-safe error handling.

function tryCatch<T, E = Error>(
  fn: () => T,
  acceptableErrors?: (new (...args: any[]) => AcceptableErrors<E>)[]
): [ExtractError<E>, null], [null, T];
tryCatchAsync

Executes an asynchronous function with type-safe error handling.

async function tryCatchAsync<T, E = Error>(
  fn: () => Promise<T>,
  acceptableErrors?: (new (...args: any[]) => AcceptableErrors<E>)[]
): Promise<[ExtractError<E>, null], [null, T]>
when

Creates a predicate pattern.

const when = <T>(predicate: (value: T) => boolean): Predicate<T> => predicate;
guard

Creates a type guard pattern.

const guard = <T>(predicate: (value: unknown) => value is T): Guard<T> => predicate;
some

Creates a pattern that matches if any element in an array matches the given pattern.

const some = <T>(pattern: Pattern<T>): Many<T> => ({
  type: 'some',
  pattern,
});
every

Creates a pattern that matches if all elements in an array match the given pattern.

const every = <T>(pattern: Pattern<T>): Many<T> => ({
  type: 'every',
  pattern,
});

Constants

  • _
    Wildcard pattern that matches any value.

    const _ = Symbol('_');
    

Examples

1. Type-Based Pattern Matching with Result

import { Ok, Err, Result, match, when } from '@jordan-hall/typeguard';

/**
 * Performs division and returns a Result type.
 * @param a The dividend.
 * @param b The divisor.
 * @returns Ok with the result if successful, Err with an error message if division by zero.
 */
function divide(a: number, b: number): Result<number, string> {
  if (b === 0) return Err("Division by zero");
  return Ok(a / b);
}

const result1 = divide(10, 2);
const result2 = divide(10, 0);

// Handling result1
const message1 = match(result1,
  { type: 'Ok', pattern: when(n => n > 5), handler: (value) => `Success: ${value} is greater than 5` },
  { type: 'Ok', pattern: _, handler: (value) => `Success: ${value}` },
  { type: 'Err', pattern: _, handler: (error) => `Error: ${error}` }
);
console.log(message1); // Output: Success: 5 is greater than 5

// Handling result2
const message2 = match(result2,
  { type: 'Ok', pattern: _, handler: (value) => `Success: ${value}` },
  { type: 'Err', pattern: "Division by zero", handler: (error) => `Caught error: ${error}` },
  { type: 'Err', pattern: _, handler: (error) => `Unhandled error: ${error}` }
);
console.log(message2); // Output: Caught error: Division by zero
import { Ok, Err, Result, match, when } from '@jordan-hall/typeguard';

interface Payment {
  method: "credit_card" | "paypal" | "bank_transfer";
  details: {
    cardNumber?: string;
    paypalId?: string;
    bankAccount?: string;
  };
  amount: number;
}

interface PaymentError {
  code: string;
  message: string;
}

/**
 * Processes a payment and returns a Result type.
 * @param payment The payment to process.
 * @returns Ok with the payment if successful, Err with an error otherwise.
 */
function processPayment(payment: Payment): Result<Payment, PaymentError> {
  if (payment.amount <= 0) {
    return Err({ code: "INVALID_AMOUNT", message: "Amount must be greater than zero" });
  }
  // Assume processing logic here...
  return Ok(payment);
}

const payment: Payment = {
  method: "paypal",
  details: {
    paypalId: "user@paypal.com"
  },
  amount: 100
};

const paymentResult = processPayment(payment);

const paymentMessage = match(paymentResult,
  // Type-based cases
  { type: 'Ok', pattern: when(p => p.amount >= 100), handler: (p) => `Large payment of \$${p.amount}` },
  { type: 'Ok', pattern: _, handler: (p) => `Payment of \$${p.amount} processed` },
  { type: 'Err', pattern: "INVALID_AMOUNT", handler: (e) => `Error: ${e.message}` },

);

console.log(paymentMessage); // Output: Large payment of $100

5. Error Handling with match

import { Ok, Err, Result, match, when } from '@jordan-hall/typeguard';

interface FileData {
  filename: string;
  content: string;
}

interface FileError {
  code: string;
  message: string;
}

/**
 * Reads a file and returns a Result type.
 * @param filename The name of the file to read.
 * @returns Ok with file data if successful, Err with a FileError otherwise.
 */
function readFile(filename: string): Result<FileData, FileError> {
  if (filename === "") {
    return Err({ code: "INVALID_FILENAME", message: "Filename cannot be empty" });
  }
  // Simulate file reading
  if (filename.endsWith(".txt")) {
    return Ok({ filename, content: "Sample text content." });
  }
  return Err({ code: "UNSUPPORTED_FORMAT", message: "File format not supported" });
}

const fileResult = readFile("data.txt");

const fileMessage = match(fileResult,
  { type: 'Ok', pattern: _, handler: (file) => `File "${file.filename}" loaded with content: ${file.content}` },
  { type: 'Err', pattern: { code: "INVALID_FILENAME" }, handler: (error) => `Error: ${error.message}` },
  { type: 'Err', pattern: { code: "UNSUPPORTED_FORMAT" }, handler: (error) => `Error: ${error.message}` }
);

console.log(fileMessage); // Output: File "data.txt" loaded with content: Sample text content.

6. Using Selector Functions in Path-Based Matching

import { Ok, Err, Result, match, when } from '@jordan-hall/typeguard';

interface Employee {
  name: string;
  department: {
    name: string;
    level: number;
  };
  projects: Array<{ title: string; hours: number }>;
}

interface EmployeeError {
  code: string;
  message: string;
}

/**
 * Retrieves employee data and returns a Result type.
 * @param id The ID of the employee.
 * @returns Ok with employee data if found, Err with an EmployeeError otherwise.
 */
function getEmployee(id: string): Result<Employee, EmployeeError> {
  if (id === "unknown") {
    return Err({ code: "NOT_FOUND", message: "Employee not found" });
  }
  return Ok({
    name: "Carol",
    department: {
      name: "Engineering",
      level: 3
    },
    projects: [
      { title: "Project A", hours: 120 },
      { title: "Project B", hours: 80 }
    ]
  });
}

const employeeResult = getEmployee("emp456");

const employeeMessage = match(employeeResult, 
  { type: 'Ok', pattern: when(employee => employee.department.level >= 3), handler: employee => `Senior ${employee.department.name} member: ${employee.name}` },
  { type: 'Ok', pattern: { projects: some(when(project => project.hours > 100)) }, handler: employee => `${employee.name} is working extensively on projects` },
  { type: 'Ok', pattern: when(employee => employee.projects.length > 5), handler: employee => `${employee.name} is handling multiple projects` },
  { type: 'Err', pattern: _, handler: error => `Error: ${error.message}` }
);

console.log(employeeMessage); // Output: Senior Engineering member: Carol

FAQs

Package last updated on 24 Oct 2024

Did you know?

Socket

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.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc