typeguardkit v0.33.0
TypeGuardKit
⚠️ API not yet stable
A TypeScript module to help construct type assertion functions and type guards.
The included classes and functions can be used to create types and their assertion functions and guards from a single source definition.
Type assertion functions and guards can be used to catch incompatible types entering your program due to data corruption, interfaces not being adhered to, or interface definitions being outdated without versioning protection from breaking changes.
Setup
Deno module URL
https://deno.land/x/typeguardkit/mod.tsnpm installation
npm install typeguardkitUsage
Example
import {
_boolean,
_null,
_number,
_PositiveInteger,
_string,
array,
Asserted,
ObjectAsserter,
union,
} from "typeguardkit";
// types/book.ts
export const _Book = new ObjectAsserter("Book", {
isbn: _string,
title: _string,
authors: array(_string),
pageCount: _PositiveInteger,
rating: union(_number, _null),
recommended: _boolean,
});
export type Book = Asserted<typeof _Book>;
// api/get_book.ts
export async function getBook(isbn: string): Promise<Book> {
const response = await fetch(`/api/books/${isbn}`);
const responseBody = await response.json();
// If `responseBody` is a `Book`, `_Book.assert` returns `responseBody` as
// `Book`. Otherwise, `_Book` throws a `TypeAssertionError`, including the
// optional value name `"responseBody"` in its `message`.
return _Book.assert(responseBody, "responseBody");
}Asserter
An Asserter<Type> has a type assertion method, assert, which should assert
whether the provided value is of Type.
interface Asserter<Type> {
readonly typeName: string;
assert(value: unknown, valueName?: string): Type;
}If value is of Type, assert should return value as Type. Otherwise,
assert should throw a TypeAssertionError, including valueName in its
message.
The module includes the _boolean, _number, _string, _null, and
_undefined primitive type Asserters.
It also includes the _NonNegativeNumber, _PositiveNumber, _Integer,
_NonNegativeInteger, and _PositiveInteger Asserters, which are number
Asserters that have additional, runtime-only constraints.
The _null and _undefined Asserters can be used to create union type
Asserters with the union function.
As well as wrapping Asserters in the
assertIs or
is functions, you can use them like this:
import { _string } from "typeguardkit";
function handleUnknown(x: unknown) {
let y;
try {
y = _string.assert(x, "x");
} catch {
return;
}
// `y` has now been initialized and inferred to be of type `string`, so can be
// passed to `handleString`. `x` is still of `unknown` type though, so cannot.
handleString(y);
}
function handleString(y: string) {}You can create your own Asserters using the TypeAsserter class. For example,
the _string Asserter was created like this:
import { TypeAsserter } from "typeguardkit";
export const _string = new TypeAsserter(
"string",
(value): value is string => typeof value === "string",
);Prefixing Asserter names with an underscore _ helps to avoid name conflicts
and shadowing.
Assertion signature wrapper
The assertIs function wraps an Asserter<Type> with an
assertion signature
so the value passed in can be narrowed to Type. If the Asserter throws an
error, it will bubble up. Otherwise, assertIs will not return a value, but
after calling it, the value passed in will be narrowed to Type.
Example:
import { _string, assertIs } from "typeguardkit";
function handleUnknown(x: unknown) {
assertIs(_string, x, "x");
// `x` has now been narrowed to type `string`, so can be passed to
// `handleString`.
handleString(x);
}
function handleString(x: string) {}Predicate signature wrapper
The is function wraps an Asserter<Type> with a
predicate signature,
creating a type guard, so the value passed in can be narrowed to Type. If the
Asserter throws an error, is will catch it and return false. Otherwise,
is will return true.
Example:
import { _string, is } from "typeguardkit";
function handleUnknown(x: unknown) {
if (is(_string, x)) {
// `x` has now been narrowed to type `string`, so can be passed to
// `handleString`.
handleString(x);
}
}
function handleString(x: string) {}NumberAsserter
A NumberAsserter is an Asserter<number>, with any additional constraints
defined by its NumberAsserterOptions properties.
The provided NumberAsserterOptions are made accessible as properties of the
created NumberAsserter.
A NumberAsserter is also a Validator<number> with a validate method, which
checks only that the provided value meets any constraints defined in the
NumberAsserterOptions, and returns any issues. This can be used to validate
user input client side, where it should already be known that value is a
number.
Example:
import { Asserted, NumberAsserter } from "typeguardkit";
export const _EvenNumberInRange = new NumberAsserter("EvenNumberInRange", {
min: { value: 0, inclusive: true },
max: { value: 100, inclusive: true },
step: 2,
});
export type EvenNumberInRange = Asserted<typeof _EvenNumberInRange>;StringAsserter
A StringAsserter is an Asserter<string>, with any additional constraints
defined by its StringAsserterOptions properties.
The provided StringAsserterOptions are made accessible as properties of the
created StringAsserter.
A StringAsserter is also a Validator<string> with a validate method, which
checks only that the provided value meets any constraints defined in the
StringAsserterOptions, and returns any issues. This can be used to validate
user input client side, where it should already be known that value is a
string.
Example:
import { Asserted, StringAsserter } from "typeguardkit";
export const _NonEmptyString = new StringAsserter("NonEmptyString", {
minLength: 1,
});
export type NonEmptyString = Asserted<typeof _NonEmptyString>;
export const _NumericString = new StringAsserter("NumericString", {
regex: { pattern: "\\d+", requirements: ["must be numeric"] },
});
export type NumericString = Asserted<typeof _NumericString>;
export const _Palindrome = new StringAsserter("Palindrome", {
rules: [
{
validate(value) {
if (value.length < 2) {
return true;
}
const forwardValue = value.replace(/[^0-9a-z]/gi, "");
const backwardValue = forwardValue.split("").reverse().join("");
return forwardValue === backwardValue;
},
requirements: ["must be a palindrome"],
},
],
});
export type Palindrome = Asserted<typeof _Palindrome>;LiteralUnionAsserter
A LiteralUnionAsserter is an Asserter for the union of its values.
The provided values are made accessible as a property of the created
LiteralUnionAsserter.
Example:
import { Asserted, LiteralUnionAsserter } from "typeguardkit";
export const _Direction = new LiteralUnionAsserter(
"Direction",
["up", "right", "down", "left"],
);
export type Direction = Asserted<typeof _Direction>;EnumAsserter
An EnumAsserter is an Asserter for the union of the member types of the
provided enumObject.
The provided enumObject is made accessible as a property of the created
EnumAsserter.
Example:
import { EnumAsserter } from "typeguardkit";
export enum Direction {
Up,
Right,
Down,
Left,
}
export const _Direction = new EnumAsserter("Direction", Direction);UnionAsserter
A UnionAsserter is an Asserter for the union of the Types of its
memberAsserters.
The provided memberAsserters are made accessible as a property of the created
UnionAsserter.
Example:
import { _null, _string, Asserted, UnionAsserter } from "typeguardkit";
export const _stringOrNull = new UnionAsserter(
"stringOrNull",
[_string, _null],
);
export type stringOrNull = Asserted<typeof _stringOrNull>;union
The union function can be used to create a UnionAsserter without specifying
a typeName.
Example:
import { _null, _string, Asserted, union } from "typeguardkit";
export const _stringOrNull = union(_string, _null);
export type stringOrNull = Asserted<typeof _stringOrNull>;ArrayAsserter
An ArrayAsserter is an Asserter for the Array type defined by its
elementAsserter, with any additional constraints defined by its
ArrayAsserterOptions properties.
The provided memberAsserter and ArrayAsserterOptions are made accessible as
properties of the created ArrayAsserter.
An ArrayAsserter is also a Validator with a validate method, which checks
only that the provided value meets any constraints defined in the
ArrayAsserterOptions, and returns any issues. This can be used to validate
user input client side, where it should already be known that value meets the
compile-time constraints of the array type.
Example:
import { _number, _string, ArrayAsserter, Asserted } from "typeguardkit";
export const _NonEmptyArrayOfString = new ArrayAsserter(
"NonEmptyArrayOfString",
_string,
{ minLength: 1 },
);
export type NonEmptyArrayOfString = Asserted<typeof _NonEmptyArrayOfString>;
export const _ArraySetOfString = new ArrayAsserter(
"ArraySetOfString",
_string,
{ mustBeASet: true },
);
export type ArraySetOfString = Asserted<typeof _ArraySetOfString>;
export const _AscendingArrayOfNumber = new ArrayAsserter(
"AscendingArrayOfNumber",
_number,
{
rules: [
{
validate(value) {
for (let i = 1; i < value.length; i++) {
if (value[i - 1] > value[i]) {
return false;
}
}
return true;
},
requirements: ["must be in ascending order"],
},
],
},
);
export type AscendingArrayOfNumber = Asserted<typeof _AscendingArrayOfNumber>;array
The array function can be used to create an ArrayAsserter without specifying
a typeName or ArrayAsserterOptions.
Example:
import { _string, array, Asserted } from "typeguardkit";
export const _ArrayOfString = array(_string);
export type ArrayOfString = Asserted<typeof _ArrayOfString>;RecordAsserter
A RecordAsserter is an Asserter for the Record type defined by its
keyAsserter and valueAsserter.
The provided keyAsserter and valueAsserter are made accessible as properties
of the created RecordAsserter.
Example:
import { _string, Asserted, RecordAsserter } from "typeguardkit";
export const _RecordOfStringByString = new RecordAsserter(
"RecordOfStringByString",
[_string, _string],
);
export type RecordOfStringByString = Asserted<typeof _RecordOfStringByString>;record
The record function can be used to create a RecordAsserter without
specifying a typeName.
Example:
import { _string, Asserted, record } from "typeguardkit";
export const _RecordOfStringByString = record(_string, _string);
export type RecordOfStringByString = Asserted<typeof _RecordOfStringByString>;ObjectAsserter
An ObjectAsserter is an Asserter for the object type defined by its
propertyAsserters.
The provided propertyAsserters are made accessible as a property of the
created ObjectAsserter.
Example:
import { _string, Asserted, ObjectAsserter, option } from "typeguardkit";
export const _User = new ObjectAsserter("User", {
name: _string,
emailAddress: option(_string),
});
export type User = Asserted<typeof _User>;ObjectIntersectionAsserter
An ObjectIntersectionAsserter is an ObjectAsserter for the intersection of
the asserted types of the provided ObjectAsserters.
Example:
import {
_string,
Asserted,
ObjectAsserter,
ObjectIntersectionAsserter,
} from "typeguardkit";
// types/entity.ts
export const _Entity = new ObjectAsserter("Entity", {
id: _string,
});
export type Entity = Asserted<typeof _Entity>;
// types/user.ts
export const _User = new ObjectIntersectionAsserter(
"User",
[
_Entity,
{
name: _string,
},
],
);
export type User = Asserted<typeof _User>;objectIntersection
The objectIntersection function can be used to create an
ObjectIntersectionAsserter without specifying a typeName.
Example:
import {
_string,
Asserted,
ObjectAsserter,
objectIntersection,
} from "typeguardkit";
// types/a.ts
export const _A = new ObjectAsserter("A", {
a: _string,
});
export type A = Asserted<typeof _A>;
// types/b.ts
export const _B = new ObjectAsserter("B", {
b: _string,
});
export type B = Asserted<typeof _B>;
// types/c.ts
export const _C = objectIntersection(_A, _B);
export type C = Asserted<typeof _C>;PartialAsserter
A PartialAsserter is an ObjectAsserter for the asserted type of the provided
ObjectAsserter with all properties set to optional.
Example:
import {
_string,
Asserted,
ObjectAsserter,
PartialAsserter,
} from "typeguardkit";
export const _Options = new PartialAsserter(
"Options",
{
option1: _string,
option2: _string,
option3: _string,
},
);
export type Options = Asserted<typeof _Options>;partial
The partial function can be used to create a PartialAsserter without
specifying a typeName.
Example:
import { _string, Asserted, ObjectAsserter, partial } from "typeguardkit";
// types/user_name.ts
export const _UserName = new ObjectAsserter("UserName", {
firstName: _string,
lastName: _string,
});
export type UserName = Asserted<typeof _UserName>;
// types/user_name_update.ts
export const _UserNameUpdate = partial(_UserName);
export type UserNameUpdate = Asserted<typeof _UserNameUpdate>;PickAsserter
A PickAsserter is an ObjectAsserter for the type constructed by picking the
set of properties Keys from the asserted type of the provided
ObjectAsserter.
Example:
import { _string, Asserted, ObjectAsserter, PickAsserter } from "typeguardkit";
// types/user.ts
export const _User = new ObjectAsserter("User", {
id: _string,
firstName: _string,
lastName: _string,
});
export type User = Asserted<typeof _User>;
// types/user_name.ts
export const _UserName = new PickAsserter(
"UserName",
_User,
["firstName", "lastName"],
);
export type UserName = Asserted<typeof _UserName>;pick
The pick function can be used to create a PickAsserter without specifying a
typeName.
Example:
import { _string, Asserted, ObjectAsserter, pick } from "typeguardkit";
// types/user.ts
export const _User = new ObjectAsserter("User", {
id: _string,
firstName: _string,
lastName: _string,
});
export type User = Asserted<typeof _User>;
// types/user_name.ts
export const _UserName = pick(_User, ["firstName", "lastName"]);
export type UserName = Asserted<typeof _UserName>;Validator
A Validator<Type> has a validate method, which should check value meets
any runtime-only constraints of Type, and return any issues. This should not
include constraints of any Validators for properties or elements of Type.
interface Validator<Type> {
validate(value: Type): string[];
}Any Asserter<Type> class that allows runtime-only constraints should also
implement Validator<Type>.
validate can then be used to validate user input client side, where it should
already be known that value meets the compile-time constraints of Type.
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago