JSPM

  • Created
  • Published
  • Downloads 839
  • Score
    100M100P100Q91484F
  • License MIT

Assertions and typeguards

Package Exports

  • @httpx/assert
  • @httpx/assert/package.json

Readme

@httpx/assert

Assertions and typeguards as primitives

npm changelog codecov bundles node browserslist size maintainability downloads license

Install

$ npm install @httpx/assert
$ yarn add @httpx/assert
$ pnpm add @httpx/assert

Features

  • 👉  Typeguards and assertions with a consistent style.
  • 🦄  Assertions with useful default error message.
  • 🖖  Optimized tree-shakability, starts at 56b.
  • 🛡️  Don't leak values in the default assertion error messages.
  • 🤗  No deps. Node, browser and edge support.

Documentation

👉 Official website, GitHub Readme or generated api doc


Introduction

Consistent style

Typeguards starts with isXXX and have an assertion counterpart named assertXXX.

Assertions error messages

When an assertion fail, a native TypeError is thrown by default with a message indicating the requirement and and information about the tested value. As an example:

expect(() => assertUuid('123')).toThrow(
  new TypeError('Value is expected to be an uuid, got: string(length:3)')
);
expect(() => assertUuid(false, undefined, { version: 1 })).toThrow(
  new TypeError('Value is expected to be an uuid v1, got: boolean(false)')
);
expect(() => assertUuidV1(Number.NaN)).toThrow(
  new TypeError('Value is expected to be an uuid v1, got: NaN')
);
expect(() => assertUuidV3(new Error())).toThrow(
  new TypeError('Value is expected to be an uuid v3, got: Error')
);
expect(() => assertUuidV4(new Date())).toThrow(
  new TypeError('Value is expected to be an uuid v4, got: Date')
);
expect(() => assertUuidV5(() => {})).toThrow(
  new TypeError('Value is expected to be an uuid v5, got: function')
);
//...

Alternatively it's possible to provide either a message or function returning an Error. For example:

import { assertEan13 } from '@httpx/assert';
import { HttpBadRequest } from '@httpx/exception';

assertEan13('123', 'Not a barcode'); // 👈 Will throw a TypeError('Not a barcode')

assertStrNotEmpty(lang, () => new HttpBadRequest('Missing language'));

Usage

assertNever

import { assertNever } from '@httpx/assert';

type PromiseState = 'resolved' | 'rejected' | 'running'
const state: PromiseState = 'rejected';
switch(state) {
  case 'resolved': return v;
  case 'rejected': return new Error();
  default:
    assertNever(state); // 👈 TS will complain about missing 'running' state
    // ☝️ Will throw a TypeError in js.
}

PS: you can use the assertNeverNoThrow with the same behaviour except that it doesn't throw and return the value instead (no runtime error).

isPlainObject

import { isPainObject, assertPlainObject } from '@httpx/assert';

isPlainObject({cool: true}); // 👈 true
isPlainObject(new Promise()); // 👈 false
assertPlainObject({});

isNumberSafeInt

import { assertNumberSafeInt, isNumberSafeInt } from '@httpx/assert';

isNumberSafeInt(10n); // 👉 false
isNumberSafeInt(BigInt(10)); // 👉 false
isNumberSafeInt(Number.MAX_SAFE_INTEGER); // 👉 true
assertNumberSafeInt(Number.MAX_SAFE_INTEGER + 1); // 👉 throws

isArrayNotEmpty

import { isArrayNotEmpty, assertArrayNotEmpty } from '@httpx/assert';

isArrayNotEmpty([]) // 👉 false
isArrayNotEmpty([0,1]) // 👉 true
assertArrayNotEmpty([]) // 👉 throws

isStrNotEmpty

import { assertStrNotEmpty, isStrNotEmpty } from '@httpx/assert';

isStrNotEmpty(''); // 👉 false
isStrNotEmpty(' '); // 👉 false: trim by default
isStrNotEmpty(' ', { trim: false }); // 👉 true: disbable trim
assertStrNotEmpty(''); // 👉 throws
assertStrNotEmpty('', undefined, { trim: false });

isStrParsableSafeInt

import { assertStrParsableSafeInt, isStrParsableSafeInt } from '@httpx/assert';

isStrParsableSafeInt(2); // 👉 false
isStrParsableSafeInt(`${Number.MAX_SAFE_INTEGER}`); // 👉 true
assertStrParsableSafeInt(`${Number.MAX_SAFE_INTEGER}1`); // 👉 throws

Uuid

isUuid

Supported uuid versions are: 1, 3, 4 and 5.

import { isUuid, isUuidV1, isUuidV3, isUuidV4, isUuidV5 } from "@httpx/assert";
import { assertUuid, assertUuidV1, assertUuidV3, assertUuidV4, assertUuidV5 } from "@httpx/assert";
import { getUuidVersion } from '@httpx/assert';

// Without version
isUuid('90123e1c-7512-523e-bb28-76fab9f2f73d'); // 👉 valid uuid v1, 3, 4 or 5
assertUuid('90123e1c-7512-523e-bb28-76fab9f2f73d');

// With version
isUuid('90123e1c-7512-523e-bb28-76fab9f2f73d', { version: 5 });
assertUuid('90123e1c-7512-523e-bb28-76fab9f2f73d', undefined, { version: 5 });
assertUuidV5('90123e1c-7512-523e-bb28-76fab9f2f73d')
isUuidV4('d9428888-122b-11e1-b85c-61cd3cbb3210'); // 👈 or isUuidV1(''), isUuidV3(''), isUuidV5('');

// Utils
getUuidVersion('90123e1c-7512-523e-bb28-76fab9f2f73d'); // 5

Barcode

isEan13

Supported barcodes is currently limited to Ean13

import { isEan13 } from "@httpx/assert";
import { assertEan13 } from "@httpx/assert";

isEan13('1234567890128'); // 👈 will check digit too
assertEan13('1234567890128');

Bundle size

Code and bundler have been tuned to target a minimal compressed footprint for the browser.

ESM individual imports are tracked by a size-limit configuration.

Scenario Size (compressed)
Import isPlainObject ~ 56b
Import isUuid ~ 175b
Import isEan13 ~ 117b
All typeguards, assertions and helpers ~ 900b

For CJS usage (not recommended) track the size on bundlephobia.

Compatibility

Level CI Description
ES2021 Dist files checked with es-check
Node16
Node18 Ensured on CI
Node20 Ensured on CI
Edge Ensured on CI with @vercel/edge-runtime
Browsers > 95% on 12/2023. Minimums to Chrome 96+, Firefox 90+, Edge 19+, iOS 12+, Safari 12+, Opera 77+
Typescript TS 4.7+ / Dual packaging is ensured with are-the-type-wrong on the CI.

For older browsers: most frontend frameworks can transpile the library (ie: nextjs...)

Acknowledgments

Special thanks for inspiration:

Contributors

Contributions are warmly appreciated. Have a look to the CONTRIBUTING document.

Sponsors

If my OSS work brightens your day, let's take it to new heights together! Sponsor, coffee, or star – any gesture of support fuels my passion to improve. Thanks for being awesome! 🙏❤️

Special thanks to

Jetbrains logo Jetbrains logo
JetBrains Embie.be

License

MIT © belgattitude and contributors.