JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 6
  • Score
    100M100P100Q35296F
  • License MIT

A simple runtime JSON type checker

Package Exports

  • typist-json

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (typist-json) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Typist JSON

minzipped size types license ci

A simple runtime JSON type checker.

Features

  • Simple. No JSON Schema, No validation rules
  • Type-safe. Written in TypeScript
  • Intuitive. Familiar syntax like TypeScript interface

Typist JSON is focused on type checking, so there is no validation rules like range of numbers or length of strings.

Install

npm install typist-json

NOTE: Require TypeScript 4.1 or higher because Typist JSON uses Key Remapping and Template Literal Types.

Example

import { j } from "typist-json";

const NameJson = j.object({
  firstname: j.string,
  lastname: j.string,
});

const UserJson = j.object({
  name: NameJson,
  age: j.number,
  "nickname?": j.string, // optional property
});

const userJson = await fetch("/api/user")
    .then(res => res.json());

if (UserJson.check(userJson)) {
  // now, the userJson is narrowed to:
  // {
  //   name: {
  //     firstname: string
  //     lastname: string
  //   }
  //   age: number
  //   nickname?: string | undefined
  // }
}

Circular References

Sometimes JSON structures can form circular references.

Typist JSON can represent circular references by wrapping checkers in the arrow function.

const FileJson = j.object({
  filename: j.string,
});

const DirJson = j.object({
  dirname: j.string,
  entries: () => j.array(j.any([FileJson, DirJson])), // references itself
});

DirJson.check({
  dirname: "animals",
  entries: [
    {
      dirname: "cat",
      entries: [
        { filename: "american-shorthair.jpg" },
        { filename: "munchkin.jpg" },
        { filename: "persian.jpg" },
      ],
    },
    {
      dirname: "dog",
      entries: [
        { filename: "chihuahua.jpg" },
        { filename: "pug.jpg" },
        { filename: "shepherd.jpg" },
      ],
    },
    { filename: "turtle.jpg" },
    { filename: "shark.jpg" },
  ],
}); // true

Type checkers

Strings

j.string.check("foo"); // true
j.string.check("bar"); // true

Numbers

j.number.check(42); // true
j.number.check(12.3); // true
j.number.check("100"); // false

Booleans

j.boolean.check(true); // true
j.boolean.check(false); // true

Literals

j.literal("foo").check("foo"); // true
j.literal("foo").check("fooooo"); // false

Arrays

j.array(j.string).check(["foo", "bar"]); // true
j.array(j.string).check(["foo", 42]); // false
j.array(j.string).check([]); // true
j.array(j.number).check([]); // true

Objects

j.object({
  name: j.string,
  age: j.number,
  "nickname?": j.string,
}).check({
  name: "John",
  age: 20,
  nickname: "Johnny",
}); // true

j.object({
  name: j.string,
  age: j.number,
  "nickname?": j.string,
}).check({
  name: "Emma",
  age: 20,
}); // true, since "nickname" is optional

j.object({
  name: j.string,
  age: j.number,
  "nickname?": j.string,
}).check({
  id: "xxxx",
  type: "android",
}); // false, since "name" and "age" is required

If a property that ends with ? is not optional, you should replace all trailing ? by ??.

More details about escaping

As mentioned above, you need to escape all trailing ? as ??.

j.object({
    "foo??": j.boolean,
}).check({
    "foo?": true,
}); // true

So if you want optional property with a name "foo???", you should use "foo???????" as key.

j.object({
  "foo???????": j.boolean,
}).check({}); // true, since "foo???" is optional

Nulls

j.nil.check(null); // true
j.nil.check(undefined); // false

Nullables

j.nullable(j.string).check("foo"); // true
j.nullable(j.string).check(null); // true
j.nullable(j.string).check(undefined); // false

Unknowns

j.unknown.check("foo"); // true
j.unknown.check(123); // true
j.unknown.check(null); // true
j.unknown.check(undefined); // true
j.unknown.check([{}, 123, false, "foo"]); // true

Unions

j.any([j.string, j.boolean]).check(false); // true

j.any([
  j.literal("foo"),
  j.literal("bar"),
]).check("foo"); // true

Get JSON type of checkers

import { j, JsonTypeOf } from "typist-json";

const UserJson = j.object({
  name: j.string,
  age: j.number,
  "nickname?": j.string,
});

type UserJsonType = JsonTypeOf<typeof UserJson>;
// 
// ^ This is same as:
// 
// type UserJsonType = {
//   name: string;
//   age: number;
//   nickname?: string;
// }