UNPKG

succulent

Version:

Powerful and easy runtime type checking

90 lines 3.74 kB
/// <reference types="jest" /> import { assertType } from "../_util"; import { check, is, or, union, $boolean, $Exact, $number, $interface, $string, $Tuple, $undefined, } from "../index"; test("$interface", () => { // The type signature of Symbol.for isn't quite correct, so we have to // assign the symbol we use here as a constant even though the whole point // of Symbol.for is to return the same symbol when called with the same // string multiple times. const key = Symbol("k"); const $Example = $interface({ a: $boolean, b: $number, c: $string, d: $interface({ [key]: $Tuple($number, $number, $number, $number), key: $Tuple($number, $number, $number, $number), }), }); const h = { a: true, b: 1, c: "hi" }; const i = { a: true, b: 1, c: "hi", d: {} }; const j = { ...i, d: { [key]: [0, 0, 0, 0] } }; const k = { ...i, d: { key: [0, 0, 0, 0] } }; const l = { ...i, d: { [key]: [0, 0, 0, 0], key: [0, 0, 0, 0], }, }; expect(is(h, $Example)).toBe(false); expect(is(i, $Example)).toBe(false); expect(is(j, $Example)).toBe(false); expect(is(k, $Example)).toBe(false); expect(is(l, $Example)).toBe(true); expect(() => check(j, $Example)).toThrowErrorMatchingSnapshot(); expect(() => check(k, $Example)).toThrowErrorMatchingSnapshot(); function _(x) { if (is(x, $Example)) { assertType(x); assertType(x); assertType(x); } } }); test("$interface with unwrapped literals", () => { expect(is({ hi: "hi" }, $interface({ hi: "hi" }))).toBe(true); expect(is({ hi: "hi" }, $interface({ hi: "hey" }))).toBe(false); }); test("$interface with optional keys", () => { const schema = $interface({ hi: $string, optional: union($string, $undefined) }); expect(is({ hi: "hi" }, schema)).toBe(true); function _(x) { if (is(x, schema)) assertType(x); } }); test("Using $interface to match an existing type", () => { // Validates that the object has a key of name with type string expect(is({}, $interface({ name: $string }))).toBe(false); // @ts-expect-error - Doesn't have name! expect(is({}, $interface({ count: $number }))).toBe(false); // Extra properties are fine expect(is({}, $interface({ name: $string, count: $number }))).toBe(false); // @ts-expect-error - string | undefined is not assignable to type string expect(is({}, $interface({ name: union($undefined, $string) }))).toBe(true); // This one works fine, because we're using Partial<Friend> instead of Friend expect(is({}, $interface({ name: or($undefined, $string) }))).toBe(true); }); test("$Exact", () => { const $State = $Exact({ a: $boolean, b: $boolean, c: $boolean }); const smol = { a: true }; const correct = { a: true, b: true, c: true }; const big = { a: true, b: true, c: true, d: true, e: true }; const wrong = { a: true, b: true, d: true }; expect(() => check(smol, $State)).toThrowErrorMatchingSnapshot(); expect(() => check(correct, $State)).not.toThrow(); expect(() => check(big, $State)).toThrowErrorMatchingSnapshot(); expect(() => check(wrong, $State)).toThrowErrorMatchingSnapshot(); expect(is(smol, $State)).toBe(false); expect(is(correct, $State)).toBe(true); expect(is(big, $State)).toBe(false); expect(is(wrong, $State)).toBe(false); }); test("`null` prototype", () => { const $Friend = $interface({ name: $string }); const billie = Object.create(null); billie.name = "Billie"; expect(is(billie, $Friend)).toBe(true); }); //# sourceMappingURL=object.test.js.map