succulent

Powerful and easy runtime type checking

Usage no npm install needed!

<script type="module">
  import succulent from 'https://cdn.skypack.dev/succulent';
</script>

README

Succulent

Powerful and easy runtime type checking

Examples

import { is, $string } from "succulent";

/**
 * Takes untrusted user input!
 */
export default function (x: unknown): string {
    if (!is(x, $string)) {
        throw new TypeError("Expected x to be a string");
    }

    // x now has type `string` and can be treated as such
    return x;
}

More complicated...

import {
    hasMaxLength,
    is,
    matches,
    Type,
    $array,
    $date,
    $object,
    $optional,
    $string,
} from "succulent";

// Use your schema definition to automatically generate TypeScript types.
// Either one of the following should work. The choice is mostly a matter of style.
export type User = Type<typeof $User>;
export interface User extends Type<typeof $User> {}

// Easily define a reuseable way to validate input from untrusted sources
export const $User = $object({
    id: $string.that(matches(/[A-Za-z0-9_-]{24}/)),
    name: $string.that(hasMaxLength(50)),
    emailAddresses: $array($string.that(matches(/[A-Za-z0-9_-]{1,}\@hey\.com/))),
    meta: $optional(
        $object({
            lastSeen: $optional($date),
        }),
    ),
});

export default function (user: unknown) {
    // You can specify a compatible generic type to use instead of the generated type
    // Mostly helpful for getting nicer editor hints
    if (!is<User>(x, $User)) {
        throw new TypeError("Expected x to be a User");
    }

    // x now has type `User`
}

Even more complicated...

import { is, reporter, inRange, $int, $object, $string } from "succulent";

type Friend = {
    name: string;
    happiness: number;
};

const $Friend = $object({
    name: $string,
    happiness: $int.that(inRange(0, 10)),
    friends: [$Friend],
});

export default function (person: unknown) {
    // Allows us to report specific validation errors
    const report = reporter();
    // Specifying `Friend` here as a generic ensures that our $Friend schema
    // is compatible with the `Friend` type
    if (!is<Friend>(person, $Friend, report)) {
        // throw a detailed validation error message
        throw report.typeError;
    }

    return person; // person has type `Friend`
}