Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

suretype

Package Overview
Dependencies
Maintainers
1
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

suretype

Typesafe JSON (Schema) validator with magic powers 🧙‍♂️

  • 1.0.1
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
36K
decreased by-3.02%
Maintainers
1
Weekly downloads
 
Created
Source

npm version downloads build status coverage status Language grade: JavaScript Node.JS version

Suretype is a JSON validator targeting TypeScript and JSON Schema. It is ridiculously type safe when used in TypeScript, which is good for accuraccy, but also for aiding IDE auto-complete.

It's as easy as Joi, but ~50x faster.

Joi x 412,045 ops/sec ±0.75% (87 runs sampled)
suretype x 22,161,985 ops/sec ±0.43% (90 runs sampled)

It supports most (if not all) of JSON schema, and nothing beyond that, so that the validator schemas written in TypeScript (or JavaScript) can be ensured to be convertible into JSON schema.

Errors are prettified using awesome-ajv-errors.

From a validator schema defined with suretype, you can trivially:

  • Compile a validator function (using the very fast Ajv)
  • Extract the corresponding JSON Schema
  • Deduce a TypeScript type corresponding to the validator schema (at compile-time!)

Minimal example

The following is a validator schema using suretype:

import { v } from "suretype"

const userSchema = v.object( {
    firstName: v.string( ).required( ),
    lastName: v.string( ),
    age: v.number( ).gte( 21 ),
} );

This schema object can be compiled into validator functions, and it can be used to deduce the corresponding TypeScript type:

import type { TypeOf } from "suretype"

type User = TypeOf< typeof userSchema >;

This type is compile-time constructed (or deduced), and is semantically identical to:

interface User {
    firstName: string;
    lastName?: string;
    age?: number;
}

Note the ? for the optional properties, i.e. those that aren't followed by required().

There are three ways of compiling a validator function; choose the one that best fits your application and situation. Given:

import { compile } from "suretype"

const data = ... // get data from somewhere, e.g. as a TypeScript unknown

Standard validator

The default behaviour of compile is to return a validator function returning decorated Ajv output.

const userValidator = compile( userSchema );
userValidator( data );
// { ok: true } or
// { ok: false, errors: [Ajv errors...], explanation: string }

The explanation is a pretty-printed error.

Type-guarded validator

Use the second optional argument to specify simple mode. The return is a boolean, type guarded.

const isUser = compile( userSchema, { simple: true } );
isUser( data ); // true | false, usable as guard:

// Realistic usage:

if ( isUser( data ) ) {
    // Valid TypeScript, <data> is now typed(!) as the User type above
    data.firstName;
} else {
     // TypeScript compile error(!), <data> is unknown
    data.firstName;
}

Type-ensured validator

Specify ensure mode to get a validator function which returns the exact same output as the input (referentially equal), but with a deduced type. This is often the most practical mode.

const ensureUser = compile( userSchema, { ensure: true } );
ensureUser( data ); // returns data or throws an error if the data isn't valid.

// Realistic usage:

const user = ensureUser( data );
// <user> is ensured to be valid, *and* is of type User (as above)
user.firstName; // string
user.foo; // TypeScript compile-time error, there is no `foo` in User

On validation failure, the error thrown will be of the class ValidationError, which has both the raw Ajv errors as an errors property, and the pretty explanation in the property explanation.

Note: The returned ensurer function can optionally take a type parameter as long as it is equal to or compatible with the deduced type. This means that if the type is exported from suretype to decorated TypeScript declaration files (with annotations), those types can be used as a type parameter, and the returned type will be that type. Example:

import type { User } from './generated/user'
const user = ensureUser< User >( data );
// user is now of type User

Decorating schemas

You can decorate a validator schema using suretype(). The return value is still a validator schema, but when exporting it, the decorations will be included.

import { suretype, v } from "suretype"

const cartItemSchema = suretype(
    // Decorations
    { name: "CartItem" },
    // The validator schema
    v.object( {
        productId: v.string( ),
        // ...
    } )
);

The decorator interface (i.e. the fields you can decorate) is:

interface Decorations {
	name: string;
	title?: string;
	description?: string;
	examples?: Array< string >;
}

where only the name is required.

Thorough example

The following are two types, one using (or depending on) the other. They are named, which will be reflected in the JSON schema, shown below.

The userSchema is the same as in the above example, although it's wrapped in suretype() which decorates it with a name and other attributes.

Given these validation schemas:

import { suretype, v } from "suretype"

const userSchema = suretype(
    {
        name: "V1User",
        title: "User type, version 1",
        description: `
            A User object must have a firstName property,
            all other properties are optional.
        `,
        examples: [
            {
                firstName: "John",
                lastName: "Doe",
            }
        ],
    },
    v.object( {
        firstName: v.string( ).required( ),
        lastName: v.string( ),
        age: v.number( ).gte( 21 ),
    } )
);

const messageSchema = suretype(
    {
        name: "V1Message",
        title: "A message from a certain user",
    },
    v.object( {
        user: userSchema.required( ),
        line: v.string( ).required( ),
    } )
);

The JSON schema for these can be extracted, either each type by itself:

import { extractSingleJsonSchema } from "suretype"

const jsonSchema = extractSingleJsonSchema( userSchema ); // The JSON schema for User

or as all types at once, into one big JSON schema. In this case, all validation schemas provided must be wrapped with suretype(), as they will become JSON schema "definitions" and therefore must have at least a name.

import { extractJsonSchema } from "suretype"

const jsonSchema = extractJsonSchema( [ userSchema, messageSchema ] );

The jsonSchema object (which can be JSON.stringify'd) will be something like:

JSON Schema

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "definitions": {
        "V1User": { // <-- This corresponds to the "name" property in suretype()
            "title": "User type, version 1",
            "description": "A User object must have a firstName property,\nall other properties are optional.",
            "examples": [
                {
                    "firstName": "John",
                    "lastName": "Doe"
                }
            ],
            "type": "object",
            "properties": {
                "firstName": { "type": "string" },
                "lastName": { "type": "string" },
                "age": { "type": "number", "minimum": 13 }
            },
            "required": [ "firstName" ]
        },
        "V1Message": {
            "title": "A message from a certain user",
            "type": "object",
            "properties": {
                "user": { "$ref": "#/definitions/V1User" }, // <-- Proper references
                "line": { "type": "string" }
            },
            "required": [ "user", "line" ]
        }
    }
}

Keywords

FAQs

Package last updated on 22 Mar 2021

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc