s-types

    1.4.1 • Public • Published

    s-types

    Library-independent type checking similar to React PropTypes

    NPM version Dependencies build status NPM license Test Coverage

    Installation

    npm install --save s-types

    Usage

    import T from 's-types';
     
    const fooType = T({
        foo: T.string,
        bar: [T.number, T.optional],
        baz: T.arrayOf(T.string)
    });
     
    const someObject = {
        foo: 'Hello',
        baz: ['world', '!']
    };
     
    fooType(someObject); // passes test, nothing logged to console
     
    const fail = {
        foo: 'Hello',
        bar: 10,
        baz: [1, 2, 3] // !!!
    };
     
    // optional second argument to provide name for better error messages
    fooType(fail, 'Bad Object');
     
    /*
        Logs the following to stderr:
     
        Failed typecheck in Bad Object
        Expected prop 'baz' of type [array of strings]
        You provided 'baz' of type [array of numbers]
     
     */

    Using an array of types in the schema allows for multiple types to be used. These are ORed together.

    // Use an array to allow multiple types
     
    const schema = T({
        foo: [T.string, T.number],
        bar: T.any
    });
     
    const someObject = {
        foo: 'Hello',
        bar: 5
    };
     
    const anotherObject = {
        foo: 5,
        bar: null
    };
     
    const badObject = {
        foo: null,
        bar: null
    };
     
    schema(someObject); // passes
    schema(anotherObject); // passes
    schema(badObject); // fails
     

    The T.schema and T.arrayOf methods allow for nesting complex structures. For example:

    const nestedRules = T({
        foo: T.string,
        bar: T.schema({
            baz: T.number,
            qux: T.arrayOf(T.arrayOf(T.number))
        })
    });
     
    const someObject = {
        foo: 'Hello',
        bar: {
            baz: 5,
            qux: [[1, 2], [3, 4]]
        }
    };
     
    nestedRules(someObject); // passes

    The T.exact and T.oneOf methods allow to restrict to an exact value. For instance, a property that must contain the value "foo" could be defined like this:

    const rules = T({
        x: T.exact('foo'),
        y: [T.exact('bar'), T.optional]
    })
     
    const obj1 = { x: 'foo' };
    const obj2 = { x: 'foo', y: 'bar' };
    const obj3 = { x: 'bar' };
     
    rules(obj1); // passes
    rules(obj2); // passes
    rules(obj3); // fails

    T.oneOf([a, b, c]) is a shorthand for [T.exact(a), T.exact(b), T.exact(c)]. It allows you to specify an array of allowed values.

    const rules = T({
        x: T.oneOf(['foo', 'bar'])
    })
     
    const obj1 = { x: 'foo' };
    const obj2 = { x: 'bar' };
    const obj3 = { x: 'baz' };
     
    rules(obj1); // passes
    rules(obj2); // passes
    rules(obj3); // fails

    Types provided

    • T.any
    • T.array (alias T.arr)
    • T.arrayOf(type) Example: T.arrayOf(T.string)
    • T.boolean (alias T.bool)
    • T.date
    • T.exact Example: T.exact('foo')
    • T.function (alias T.fn)
    • T.integer (alias T.int)
    • T.nil (prop is null or undefined)
    • T.not(type) Example: T.not(T.string)
    • T.number (alias T.num)
    • T.null (alias T.NULL)
    • T.object (alias T.obj)
    • T.oneOf Example: T.oneOf(['foo', 'bar'])
    • T.optional (alias T.undefined)
    • T.schema (alias T.interface) Example: T.schema({ foo: T.string, bar: T.number })
    • T.string (alias T.str)

    Custom types

    If the provided types are not sufficient, you can provide a custom type checking function to s-types.

    These functions take one argument (the value of the property to be type checked) and return a boolean to indicate whether it is valid or not.

    The function must also be assigned a type attribute in order to allow for helpful error messages.

    For example, T.string is defined as follows:

    T.string = function(x) {
        return typeof x === 'string';
    };
     
    T.str.type = 'string';

    To create a positiveNumber type, you could do the following:

    function positiveNumber(x) {
        return typeof x === 'number' && x > 0;
    }
     
    postiveNumber.type = 'positive number';
     
    const schema = {
        n: positiveNumber
    };
     
    const obj = {
        n: 12
    };
     
    T(schema)(obj); // passes

    Usage in production

    This should only be used in development and test environments, so when in production there is a mode that turns type checking into a noop.

    Just set T.disabled to true before running any type checking.

    One way to do this would be the following:

    import T from 's-types';
     
    T.disabled = process.env.node_env === 'production';
     
    const fooType = T({
        foo: T.string
    });
     
    const fail = {
        foo: 5
    };
     
    // in a development environment, this logs an error message
    // when process.env.node_env === 'production', this logs nothing
    fooType(fail, 'Bad Object');

    Usage in test environments

    There is an option to change the typecheckers to throw rather than log to console.error. This can be enabled in test environments to make typechecking testable without having to check for messages in stdout.

    import T from 's-types';
     
    T.throws = true;
     
    const fooType = T({
        foo: T.string
    });
     
    const fail = {
        foo: 5
    };
     
    fooType(fail, 'Bad Object'); // throws a TypeError

    Why two functions?

    The T(a)(b, c?); syntax allows typecheckers to be reused.

    For example:

    const UserType = T({
        age: T.number,
        email: T.string,
        emailVerified: T.boolean,
        name: T.string,
        friends: T.arrayOf(T.string)
    });
     
    const user1 = {
        age: 21,
        email: example@gmail.com,
        emailVerified: false,
        name: 'John Doe',
        friends: ['user2']
    };
     
    const user2 = {
        age: 24,
        email: example@yahoo.com,
        emailVerified: true,
        name: 'Jane Doe',
        friends: ['user1']
    };
     
    UserType(user1, 'John Doe user object'); // passes
    UserType(user2, 'Jane Doe user object'); // passes
     
    // The `UserType` typechecker can now be exported and used elsewhere

    Things to note

    In most cases, the return value happens to be null when there are no errors or a string if a type mismatch occurred. For some structures, like T.schema, this does not always hold true and should not be relied upon. The only reliable output is whatever is logged to stderr (or the TypeError that is thrown if T.throws is enabled). In addition, when T.disabled is set to true, the return value will always be undefined.

    Keywords

    Install

    npm i s-types

    DownloadsWeekly Downloads

    1

    Version

    1.4.1

    License

    MIT

    Last publish

    Collaborators

    • seabass