sundryjs
TypeScript icon, indicating that this package has built-in type declarations

0.1.4 • Public • Published

SundryJS

A collection of useful functions, types, and objects.

Installation

Install this module with the following command:

npm install sundryjs

Add the module to your package.json dependencies:

npm install --save sundryjs

Add the module to your package.json dev-dependencies:

npm install --save-dev sundryjs

Import a module as follows:

import nullThrows from "sundryjs/assert/nullThrows";

For types, import it like this:

import type { Opaque } from "sundryjs/types/Opaque";

Reference

EventEmitter

The EventEmitter module implements a generic typed event emitter.

class EventEmitter<T>

T defines an object keyed by the event name and the value being the event type.

The listen method starts listening to specific events, executing the callback when the event is triggered.

listen<E extends string & keyof T>(
    event: E,
    cb: (data: T[E]) => void,
): EventSubscription

Starts listening to all events, using the callback when the event is triggered.

Note: This method does not listen to the payload, but only the event name. The payload is not sent into the callback as with listen. Use this only for information purposes. Also, use this sparingly as it can become quite expensive.

listenToAll<E extends string & keyof T>(
    cb: (event: E) => void,
): EventSubscription

Triggers an event with the typed payload.

trigger<E extends string & keyof T>(event: E, payload: T[E]): void

Convenience function to remove a subscription. You can also use the EventSubscription interface returned from the listen methods.

remove(subscription: EventSubscription): void

Removes all subscribers from the event emitter.

removeAll(): void

The EventSubscription interface is defined as:

interface EventSubscription {
    remove: () => void;
}

Usage:

type Events = {
    "auth:login:changed": {
        user: string,
        permissions: number,
    };
    // Any other event
};

class GlobalEventEmitter extends EventEmitter<Events> {}

const globalEvents = new GlobalEventEmitter();

// Listen to events fully typed
const subscription = globalEvents.listen("auth:login:changed", payload => {
    console.log(`User ${payload.user} logged in with permission value ${payload.permissions}`);
});

// Trigger events requiring to supply the right payload fields
globalEvents.trigger("auth:login:changed", {
    user: "Anthony",
    permissions: 0755,
});

// Remove subscription
subscription.remove();

The remove method removes the subscription from the event emitter.

Assert

assert/assertNever

A function that fails for all calls.

This is used for exhausive checking switches and similar use-cases.

assertNever(x: unknown): never

Usage:

The following code makes sure that value is either 1 or 2. Due to typing, TypeScript will be able to recognize this and statically suggests this error case.

switch (value) {
    case 1:
        // some code
        break;
    case 2:
        // some other code
        break;

    default:
        assertNever(value);
}

assert/doNotThrowWithDetails

Handles the exception according to the environment.

Use this function in try/catch exceptions when you do not want to throw, but keep track of the issue in a development environment. The values will be written to the console when __DEV is set, otherwise it will be ignored.

If no msg was given, then it will try to derive it from the non-standard internalMessage field and will fall back to the standard message field. The data values will be printed with the msg in a collapsible console entry.

doNotThrowWithDetails(
    err: Error,
    msg?: string,
    data?: Record<string, unknown>,
): void

Usage:

try {
    // some code that might throw an exception
} catch(Error err) {
    doNotThrowWithDetails(
        err,
        null, // use message from error
        { // Values which will be printed in the console log supporting debugging
            foo: 23,
        },
    );
}

assert/invariant

Use invariant() to assert a state which your program assumes to be true.

Use template string to give more context on what went wrong.

The invariant message will be stripped in production, but the invariant will remain to ensure logic does not differ in production.

invariant(condition: unknown, msg?: string): asserts condition

Usage:

const value = someFunction(); // Might be any type
invariant(typeof value === "string", "Value is not a string.");
// Can be sure it is a string now

assert/nullThrows

Util function to return the non-null (and non-undefined) type to keep everything strictly typed. Use template string to give more context on what went wrong.

nullThrows<T>(x: T | null | undefined, msg?: string): T

Usage:

const value = someFunction(); // Returns number | null | undefined
const numberValue = nullthrows(value, "Value is null.");
// numberValue is now of type "number"

assert/throwWithDetails

Handles the exception according to the environment.

Use this function in try/catch exceptions when you still want to throw. This is very similar to doNotThrowWithDetails, but it will throw an exception. However, it will also in addition write the context data to the console in a development environment when __DEV is set.

No msg will automatically be derived in this case. The data values will be printed with the msg, if available, in a collapsible console entry.

The return value gives TypeScript context that it will never return.

throwWithDetails(
    err: Error,
    msg?: string,
    data?: Record<string, unknown>,
): never

Usage:

try {
    // some code that might throw an exception
} catch(Error err) {
    throwWithDetails(
        err, // Will re-throw this error
        null, // use message from error
        { // Values which will be printed in the console log supporting debugging
            foo: 23,
        },
    );
}

assert/undefinedThrows

Util function to return the non-undefined (only) type to keep everything strictly typed. Use template string to give more context on what went wrong.

undefinedThrows<T>(x: T | undefined, msg?: string): T

Usage:

const value = someFunction(); // Returns number | undefined
const numberValue = nullthrows(value, "Value is undefined.");
// numberValue is now of type "number"

Collection

collection/firstX

Returns the first entry and will fail if none available.

firstX<T>(items: T[], msg?: string): T

Usage:

const firstEntry = firstX(list); // Fails when list is empty

collection/flatten

Flattens a list within a list to only return a single-depth list.

flatten<T>(items: T[][]): T[]

Usage:

const complexList = [
    [1, 2, 3],
    [4, 5, 6],
];
const thinList = flatten(complexList);
// thinList = [1, 2, 3, 4, 5, 6]

collection/lastX

Returns the first entry and will fail if not available.

lastX<T>(items: T[], msg?: string): T

Usage:

const lastEntry = lastX(list); // Fails when list is empty

collection/nthX

Returns the first entry and will fail if not available.

Note: The index starts at zero.

nthX<T>(items: T[], idx: number, msg?: string): T

If msg is not given, a useful message will be returned.

Should the xth entry be undefined, then it will trigger an error.

Usage:

const fifthEntry = nthX(list, 4); // Fails when there is no 5th entry

collection/onlyX

Returns the first entry and will fail if there are none or more than one entry available.

onlyX<T>(items: T[], msg?: string): T

Usage:

const list = someFunction(); // Will return a list, but it is expected to be one entry
const entry = onlyX(list); // Fails when there is no or more than one entry

Str

str/camelCase

Converts a string to camel-case.

Examples: foo-bar -> fooBar FooBar -> fooBar fooBar -> fooBar foo_bar -> fooBar

camelCase(str: string): string

str/kebabCase

Converts a string to kebab-case.

Examples: foo-bar -> foo-bar FooBar -> foo-bar fooBar -> foo-bar foo_bar -> foo-bar

kebabCase(str: string): string

str/pascalCase

Converts a string to pascal-case.

Examples: foo-bar -> FooBar FooBar -> FooBar fooBar -> FooBar foo_bar -> FooBar

pascalCase(str: string): string

str/snakeCase

Converts a string to snake-case.

Examples: foo-bar -> foo_bar FooBar -> foo_bar fooBar -> foo_bar foo_bar -> foo_bar

snakeCase(str: string): string

Time

time/time

Utility functions for time.

Following is a list of self-explanatory functions:

secToMs(seconds: number): number
msToSecs(ms: number): number
minsToSecs(minutes: number): number
secsToMins(secs: number): number
hrsToSecs(hours: number): number
secsToHrs(secs: number): number
daysToSecs(days: number): number
secsToDays(secs: number): number
weeksToSecs(weeks: number): number
secsToWeeks(secs: number): number
monthsToSecs(months: number): number
secsToMonths(secs: number): number
quartersToSecs(quarters: number): number
secsToQuarters(secs: number): number
halvesToSecs(halves: number): number
secsToHalves(secs: number): number
yearsToSec(years: number): number
secsToYears(secs: number): number

Types

types/isType

Type guard for runtime. It converts an input type to an output type according to some condition defined.

isType<T>(value: unknown, condition: boolean): value is T

Usage:

const value = isType(inputValue, typeof inputValue = "string");

types/ObjectPattern

Converts an object with string keys to a typed object.

Note: Make sure to mark the object as <const> as this is required.

type ObjectPattern<T>

Usage:

const payload = <const>{
    id: "number",
    username: "string",
};
type Payload = ObjectPattern<typeof payload>;
// Payload is of type
// {
//   id: number,
//   username: string,
// }

types/Opaque

Defines an opaque type for TypeScript.

Note: Make sure you give the K a unique identifier across the system.

type Opaque<K, T>

Usage:

// A function which requires a specific type
function login(userID: UserID): void {
    // Do the login
}

// Define Opaque type
type UserID = Opaque<"UserID", number>;

// Define a function to convert from a number value to the Opaque type
function makeUserID(userID: number): UserID {
    return userID as UserID;
}

// Convert a validated input to the Opaque value
const user_id = makeUserID(validateUserID(input_user_id));

// Call function
login(user_id);

// Will FAIL
login(input_user_id);

types/StringToType

Returns the type of a particular string literal

Converts a "string" literal into the string type, and many others.

type StringToType<T>

The following types are supported:

  • "string" -> string
  • "number" -> number
  • "boolean" -> boolean
  • "undefined" -> undefined
  • "function" -> Function
  • "object" -> Record<string, any>

types/TypeToString

Returns the type of a particular string literal

Converts a "string" literal into the string type, and many others.

type TypeToString<T>

The following types are supported:

  • string -> "string"
  • number -> "number"
  • boolean -> "boolean"
  • undefined -> "undefined"
  • Function -> "function"
  • Record<string, any> -> { [K in keyof T]: TypeToString<T[K]> }
  • T -> any
  • null -> "null"

Note: This type uses a recursive call and an object will be broken down into individual strings.

Verify

verify/hasOwnProperty

Safer wrapper around hasOwnProperty.

See https://eslint.org/docs/rules/no-prototype-builtins

hasOwnProperty(
    obj: Record<string, unknown>,
    property: string,
): boolean

verify/hasSameProperties

Determines if two object have the same properties.

hasSameProperties(
    a: Record<string | number | symbol, any>,
    b: Record<string | number | symbol, any>,
): boolean

verify/objectPatternVerify

Verifies that a specific object has the structure as defined in an object pattern. It will throw when the type is not as expected.

objectPatternVerify<T>(
    desc: string,
    pattern: Record<string, ObjectPatternTypes>,
    values: T,
    options?: { fail?: boolean },
): T | null

Usage:

const pattern = {
    name: "string",
    age: "number",
};
const values = {
    name: "John Doe",
    age: 23,
};
const result = objectPatternVerify("<What is this?>", pattern, values);
// Will be null if it isn't of this type as defined above,
// but will return the value if it is

Readme

Keywords

none

Package Sidebar

Install

npm i sundryjs

Weekly Downloads

1

Version

0.1.4

License

SEE LICENSE IN LICENSE

Unpacked Size

33 kB

Total Files

55

Last publish

Collaborators

  • marcelerz