UNPKG

type-assurance

Version:

Lightweight type guards and assertions

288 lines 9.45 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const tap_1 = __importDefault(require("tap")); const index_js_1 = require("../index.js"); tap_1.default.test("string", async (t) => { const s = "s"; const isString = (0, index_js_1.is)(s, String); if (isString) { s.startsWith("s"); } t.ok(isString); }); tap_1.default.test("number", async (t) => { const s = 42; const isNumber = (0, index_js_1.is)(s, Number); if (isNumber) { s.toFixed(2); } t.ok(isNumber); }); tap_1.default.test("boolean", async (t) => { const s = true; t.ok((0, index_js_1.is)(s, Boolean)); }); tap_1.default.test("object", async (t) => { const obj = { name: "aaa", count: 1 }; const matches = (0, index_js_1.is)(obj, { name: String, count: Number }); if (matches) { obj.name.charAt(0); obj.count.toFixed(2); } t.ok(matches); }); tap_1.default.test("null", async (t) => { const v = null; t.ok((0, index_js_1.is)(v, null)); t.notOk((0, index_js_1.is)(v, { name: String })); }); tap_1.default.test("undefined", async (t) => { const v = undefined; t.ok((0, index_js_1.is)(v, undefined)); t.notOk((0, index_js_1.is)(v, null)); }); tap_1.default.test("nested object", async (t) => { const obj = JSON.parse(`{ "post": { "id": 23 } }`); const matches = (0, index_js_1.is)(obj, { post: { id: Number } }); if (matches) { obj.post.id.toFixed(2); } t.ok(matches); }); tap_1.default.test("instance", async (t) => { const d = new Date(); const matches = (0, index_js_1.is)(d, Date); if (matches) { d.getTime(); } t.ok(matches); }); tap_1.default.test("class instance", async (t) => { class Foo { constructor() { this.bar = 42; } } const foo = new Foo(); const matches = (0, index_js_1.is)(foo, Foo); if (matches) { foo.bar; } t.ok(matches); }); tap_1.default.test("array", async (t) => { const a = [1, 2, 3]; const matches = (0, index_js_1.is)(a, [Number]); if (matches) { a.map((n) => n.toFixed(2)); } t.ok(matches); }); tap_1.default.test("array item type mismatch", async (t) => { const a = ["a", "b", "c"]; const matches = (0, index_js_1.is)(a, [Number]); t.notOk(matches); }); tap_1.default.test("not an array", async (t) => { const a = { 0: "a", 1: "b" }; const matches = (0, index_js_1.is)(a, [String]); t.notOk(matches); }); tap_1.default.test("mixed array", async (t) => { const a = ["a", 1, true]; const matches = (0, index_js_1.is)(a, []); t.ok(matches); }); tap_1.default.test("tuple", async (t) => { const a = ["A", 2, new Date()]; const matches = (0, index_js_1.is)(a, [String, Number, Date]); if (matches) { a[0].charAt(0); a[1].toFixed(2); a[2].getTime(); } t.ok(matches); t.notOk((0, index_js_1.is)(a, [String, Number, String])); }); tap_1.default.test("unsupported schema", async (t) => { const matches = (0, index_js_1.is)("", Symbol()); t.notOk(matches); }); tap_1.default.test("arrow function", async (t) => { t.ok((0, index_js_1.is)("foo", (v) => typeof v === "string")); t.notOk((0, index_js_1.is)("foo", (v) => typeof v === "number")); }); tap_1.default.test("function declaration", async (t) => { function isArray(v) { return Array.isArray(v); } t.ok((0, index_js_1.is)([], isArray)); }); tap_1.default.test("Array", async (t) => { t.ok((0, index_js_1.is)([], Array)); t.ok((0, index_js_1.is)(["abc", 123], Array)); t.notOk((0, index_js_1.is)({}, Array)); }); tap_1.default.test("Array.isArray", async (t) => { t.ok((0, index_js_1.is)([], Array.isArray)); t.ok((0, index_js_1.is)(["abc", 123], Array.isArray)); t.notOk((0, index_js_1.is)({}, Array.isArray)); }); tap_1.default.test("unknown", async (t) => { t.ok((0, index_js_1.is)(23, index_js_1.unknown)); t.ok((0, index_js_1.is)("abc", index_js_1.unknown)); t.ok((0, index_js_1.is)([], index_js_1.unknown)); t.ok((0, index_js_1.is)({}, index_js_1.unknown)); t.ok((0, index_js_1.is)(undefined, index_js_1.unknown)); t.ok((0, index_js_1.is)(null, index_js_1.unknown)); }); tap_1.default.test("union", async (t) => { const a = { foo: "bar" }; const b = { foo: 42 }; t.ok((0, index_js_1.is)(a, { foo: (0, index_js_1.union)(String, Number) })); t.ok((0, index_js_1.is)(b, { foo: (0, index_js_1.union)(String, Number) })); t.notOk((0, index_js_1.is)(a, { foo: (0, index_js_1.union)(Boolean, Number) })); const isStringOrNumber = (0, index_js_1.union)(String, Number); t.ok((0, index_js_1.is)(23, isStringOrNumber)); t.ok((0, index_js_1.is)("hello", isStringOrNumber)); t.notOk((0, index_js_1.is)(false, isStringOrNumber)); }); tap_1.default.test("optional", async (t) => { const a = { foo: "foo" }; const b = { foo: undefined }; const c = {}; t.ok((0, index_js_1.is)(a, { foo: (0, index_js_1.optional)(String) })); t.ok((0, index_js_1.is)(b, { foo: (0, index_js_1.optional)(String) })); t.ok((0, index_js_1.is)(c, { foo: (0, index_js_1.optional)(String) })); const isStringOrUndefined = (0, index_js_1.optional)(String); t.ok((0, index_js_1.is)("hello", isStringOrUndefined)); t.ok((0, index_js_1.is)(undefined, isStringOrUndefined)); t.notOk((0, index_js_1.is)(23, isStringOrUndefined)); }); tap_1.default.test("literal", async (t) => { const a = "foo"; t.ok((0, index_js_1.is)(a, "foo")); t.ok((0, index_js_1.is)(a, (0, index_js_1.union)("foo", "bar"))); t.notOk((0, index_js_1.is)(a, "bar")); }); tap_1.default.test("object with literal", async (t) => { const obj = { name: "aaa", count: 1 }; const matches = (0, index_js_1.is)(obj, { name: "aaa", count: Number }); if (matches) { obj.name.charAt(0); obj.count.toFixed(2); } t.ok(matches); }); tap_1.default.test("assert", async (t) => { const obj = { foo: "foo" }; (0, index_js_1.assert)(obj, { foo: String }); t.throws(() => { (0, index_js_1.assert)(obj, { foo: Number }); }, TypeError); }); tap_1.default.test("TypeFromSchema", async (t) => { let s = "foo"; //@ts-expect-error s = 23; let i = 23; //@ts-expect-error i = "foo"; const isStringOrNumber = (0, index_js_1.union)(String, Number); let x = 23; x = "foo"; //@ts-expect-error x = false; const fooSchema = { required: { value: String, }, optional: (0, index_js_1.optional)(String), }; let foo = { required: { value: "", }, }; foo.optional = "foo"; //@ts-expect-error foo.optional = 23; }); tap_1.default.test("typeGuard", async (t) => { const isString = (0, index_js_1.typeGuard)(String); t.ok(isString("foo")); t.notOk(isString(23)); let isNumber; isNumber = (0, index_js_1.typeGuard)(Number); t.ok(isNumber(23)); //@ts-expect-error isNumber = isString; }); tap_1.default.test("diff", async (t) => { t.match((0, index_js_1.diff)("abc", Number), ["value"]); t.match((0, index_js_1.diff)({ num: "aaa", val: "bbb" }, { num: Number, val: String }), [ "value.num", ]); }); tap_1.default.test("deeply nested schemas", async (t) => { const schema = { level1: (0, index_js_1.optional)({ level2: { level3: { level4: { level5: { level6: { level7: { level8: { level9: { level10: { value: String, }, }, }, }, }, }, }, }, }, }), }; const value = {}; t.ok((0, index_js_1.is)(value, schema)); }); tap_1.default.test("record", async (t) => { const obj = { foo: "foo" }; (0, index_js_1.assert)(obj, (0, index_js_1.record)(String, String)); t.throws(() => { (0, index_js_1.assert)(obj, (0, index_js_1.record)(String, Number)); }, TypeError); }); tap_1.default.test("nested record", async (t) => { // Define schemas const recordSchema = (0, index_js_1.record)(String, index_js_1.unknown); const TestSchema = { record: recordSchema, }; // Test empty record const s = {}; t.ok((0, index_js_1.is)(s, recordSchema), "empty record should be valid"); // Test nested record in object const test = { record: s, }; t.ok((0, index_js_1.is)(test, TestSchema), "object with record should be valid"); // Test with actual data const populatedTest = { record: { key1: "string", key2: 42, key3: { nested: true }, }, }; t.ok((0, index_js_1.is)(populatedTest, TestSchema), "object with populated record should be valid"); }); //# sourceMappingURL=index.js.map