Skip to content

frantisekstanko/assertion

Repository files navigation

assertion

CI npm version License: MIT codecov Bundle Size TypeScript

Type-safe assertion library for TypeScript with runtime validation and type narrowing.

Features

  • 🎯 Type-safe - Full TypeScript support with type narrowing
  • 🏗️ Custom exceptions - Use your own domain exceptions for Hexagonal/Clean Architecture
  • 🚀 Zero dependencies - Lightweight and fast
  • 🔒 Runtime validation - Validate unknown data at runtime
  • 📦 Tree-shakeable - Only bundle what you use
  • 🌐 Universal - Works in Node.js and browsers (see Browser Support)

Installation

npm install @frantisekstanko/assertion

Usage

Basic Example

import { Assertion } from '@frantisekstanko/assertion'

function processData(value: unknown) {
  Assertion.string(value)
  // value is now typed as string
}

API

Type Assertions

Assertion.string(value, message?)

Assert value is a string.

Assertion.string('hello') // ✓ passes
Assertion.string(123) // ✗ throws

Assertion.number(value, message?)

Assert value is a finite number (not NaN or Infinity).

Assertion.number(42) // ✓ passes
Assertion.number(3.14) // ✓ passes
Assertion.number(NaN) // ✗ throws
Assertion.number(Infinity) // ✗ throws

Assertion.greaterThan(value, threshold, message?)

Assert value is a number greater than a threshold.

Assertion.greaterThan(10, 5) // ✓ passes
Assertion.greaterThan(5, 5) // ✗ throws
Assertion.greaterThan(3, 5) // ✗ throws

Assertion.lessThan(value, threshold, message?)

Assert value is a number less than a threshold.

Assertion.lessThan(3, 5) // ✓ passes
Assertion.lessThan(5, 5) // ✗ throws
Assertion.lessThan(10, 5) // ✗ throws

Assertion.nullOrString(value, message?)

Assert value is a string or null.

Assertion.nullOrString('hello') // ✓ passes
Assertion.nullOrString(null) // ✓ passes
Assertion.nullOrString(undefined) // ✗ throws

Assertion.nullOrNumber(value, message?)

Assert value is a finite number or null.

Assertion.nullOrNumber(42) // ✓ passes
Assertion.nullOrNumber(null) // ✓ passes
Assertion.nullOrNumber(NaN) // ✗ throws
Assertion.nullOrNumber(Infinity) // ✗ throws

Assertion.notNull(value, message?)

Assert value is not null or undefined.

Assertion.notNull('hello') // ✓ passes
Assertion.notNull(0) // ✓ passes
Assertion.notNull(null) // ✗ throws
Assertion.notNull(undefined) // ✗ throws

Assertion.array(value, message?)

Assert value is an array.

Assertion.array([1, 2, 3]) // ✓ passes
Assertion.array([]) // ✓ passes
Assertion.array('not array') // ✗ throws

Assertion.object(value, message?)

Assert value is a plain object (not an array or null).

Assertion.object({}) // ✓ passes
Assertion.object({ a: 1 }) // ✓ passes
Assertion.object([]) // ✗ throws
Assertion.object(null) // ✗ throws

Assertion.boolean(value, message?)

Assert value is a boolean.

Assertion.boolean(true) // ✓ passes
Assertion.boolean(false) // ✓ passes
Assertion.boolean(1) // ✗ throws

Assertion.nullOrBoolean(value, message?)

Assert value is a boolean or null.

Assertion.nullOrBoolean(true) // ✓ passes
Assertion.nullOrBoolean(null) // ✓ passes
Assertion.nullOrBoolean(undefined) // ✗ throws

Assertion.function(value, message?)

Assert value is a function.

Assertion.function(() => {}) // ✓ passes
Assertion.function(Math.max) // ✓ passes
Assertion.function({}) // ✗ throws

Assertion.minLength(value, min, message?)

Assert value is a string or array with minimum length.

Assertion.minLength('hello', 3) // ✓ passes
Assertion.minLength([1, 2, 3], 2) // ✓ passes
Assertion.minLength('hi', 5) // ✗ throws

Assertion.maxLength(value, max, message?)

Assert value is a string or array with maximum length.

Assertion.maxLength('hello', 10) // ✓ passes
Assertion.maxLength([1, 2], 5) // ✓ passes
Assertion.maxLength('toolong', 3) // ✗ throws

Assertion.regex(value, pattern, message?)

Assert value is a string matching a regular expression.

Assertion.regex('abc123', /^[a-z]+[0-9]+$/) // ✓ passes
Assertion.regex('123abc', /^[a-z]+[0-9]+$/) // ✗ throws

Assertion.email(value, message?)

Assert value is a valid email address.

Assertion.email('[email protected]') // ✓ passes
Assertion.email('invalid-email') // ✗ throws

Assertion.url(value, message?)

Assert value is a valid URL.

Assertion.url('https://example.com') // ✓ passes
Assertion.url('not-a-url') // ✗ throws

Assertion.uuid(value, message?)

Assert value is a valid UUID.

Assertion.uuid('550e8400-e29b-41d4-a716-446655440000') // ✓ passes
Assertion.uuid('invalid-uuid') // ✗ throws

Assertion.instanceOf(value, constructor, message?)

Assert value is an instance of a constructor.

class MyClass {}
const instance = new MyClass()
Assertion.instanceOf(instance, MyClass) // ✓ passes
Assertion.instanceOf({}, MyClass) // ✗ throws

Error Handling

All assertion methods throw AssertionException when validation fails. You can catch and handle these exceptions:

import { Assertion, AssertionException } from '@frantisekstanko/assertion'

try {
  Assertion.string(123)
} catch (error) {
  if (error instanceof AssertionException) {
    console.error('Validation failed:', error.message)
  }
}

Custom Exception Classes

Keep your domain layer clean and vendor-agnostic by using your own exception classes. This is especially valuable in Hexagonal/Clean Architecture where you want to avoid coupling your domain to third-party libraries.

Extend the Assertion class to throw your own domain exceptions:

import { Assertion } from '@frantisekstanko/assertion'

// Your domain exception in the core layer
class DomainValidationError extends Error {
  constructor(message: string) {
    super(message)
    this.name = 'DomainValidationError'
  }
}

// Create your domain-specific assertion class
class DomainAssertion extends Assertion {
  protected static createException(message: string): Error {
    return new DomainValidationError(message)
  }
}

Now your domain layer only knows about DomainValidationError, not the assertion library:

// In your domain layer - no vendor coupling!
try {
  DomainAssertion.string(userInput)
  DomainAssertion.email(email)
} catch (error) {
  if (error instanceof DomainValidationError) {
    // Handle with your domain error handling strategy
  }
}

This approach maintains the dependency inversion principle - your core domain doesn't depend on external libraries.

Browser Support

This library is fully compatible with modern browsers. It uses only standard JavaScript features available across all modern browser environments:

  • No Node.js-specific APIs - Zero dependencies on Node.js runtime features like fs, process, or path
  • Universal JavaScript - Only uses standard APIs: typeof, Array.isArray(), isNaN(), isFinite(), and the URL constructor
  • Modern JavaScript - Compiled to ES2022, supported by all current browsers

You can use it directly in browser applications, web workers, or any JavaScript runtime without modification.

License

MIT © Frantisek Stanko

About

Type-safe assertion library for TypeScript with runtime validation and type narrowing.

Resources

License

Stars

Watchers

Forks