Runtime typechecking
npm install ts-castRuntime type checking for Typescript and JavaScript projects. It allows to specify data structures
of the "external" resources (requests to the application or responses from other applications).
The idea is based on the Caster that is a function accepts value of unknown type
and returns value of target type or throws a TypeError if casting is impossible.
Additionally ts-cast presents tools for:
- validation casted data
- transformation of casted data
- Either and Validation monads support
Almost in all cases ts-cast allows to avoid specification of correspondent type in TypeScript,
because the type could be get as ReturnType of the correspondent caster-function.
``ts
const Person = struct({ name: string, age: integer });
type Person = ReturnType
// the same as
type Person = { name: string, age: number };
`
`shell`
npm i ts-cast
Read ts-cast documentation on github:
https://github.com/DScheglov/ts-cast/tree/master/docs
Let's start with an example:
./src/schema.ts
`typescript
import { integer, number, string, struct, tuple, array, toBe } from 'ts-cast';
import v from 'validator';
export const Person = struct({
name: string,
email: string.restrict(toBe(v.isEmail, "a valid email")),
});
export const Coords = tuple(number, number);
export const Book = struct({
title: string,
annotation: string.optional,
year: integer,
authors: array(Person),
coords: Coords.optional,
});
export type TPerson = ReturnType
export type TCoords = ReturnType
export type TBook = ReturnType
`
Then we can use defined types and their caster-s in this way:
./src/index.ts
`typescript
import { Person, TPerson, Book, TBook } from './schema';
const me = Person({ name: "John Smith", email: "john@smith.com" });
const meAgain: TPerson = {
name: "John Smith",
email: "john.smith@gmail.com", // but email will not be validated with validator.isEmail
};
const myBook = Book({
title: "My First Book",
year: 2021,
authors: [
me,
meAgain,
{ name: 'Some Other Guy', email: 'other.guy@gmail.com' },
],
coords: [1.2, 23.32]
}, "myBook");
const book: TBook = myBook;
console.dir(book, { depth: null });
`
| ts-cast | TypeScript |
| :-------: | :---------: |
| number | number |integer
| | number |string
| | string |boolean
| | boolean |nil
| | null |undef
| | undefined |
Example:
`ts
import { integer } from 'ts-cast';
const x = integer(10); // works
const y = integer(Math.PI); // throws TypeError
const z = integet('10'); // also throws TypeError
`
`ts
import { string } from 'ts-cast';
const a = string('Hello Wordl!'); // works
const b = string(''); // also works
const c = string(null); // throws TypeError
const d = string(20); // throws TypeError again
`
| ts-cast | TypeScript | Comments |
| :--------------------: | :---------------: | :---------------------------------------------------------- |
| value(V) | V as const | V extends number \| string \| boolean \| symbol |values(A, B, C, ...)
| | A \| B \| C ... | A, B, C ... extends number \| string \| boolean \| symbol |
`ts
import { values } from 'ts-cast';
const TrafficLight = values('red', 'yellow', 'green');
const green = TrafficLight('green'); // works
type TypeOfGreen = typeof green; // 'red' | 'yellow' | 'green'
const wrong = TrafficLight('blue'); // throws TypeError
`
| ts-cast | TypeScript |
| :--------------------------------------: | :-------------: |
| tuple(caster | [T1, T2, ...] |array(caster
| | T[] |struct({ a: caster, b: caster })
| | { a: A, b: B } |record(caster
| | Record |
| ts-cast | TypeScript |
| :-----------------------: | :--------------: |
| caster | T \| undefined |caster
| | x: T = v |caster
| | T \| null |caster
| | T |
| ts-cast | TypeScript |
| :----------------------------------: | :---------------: |
| union(caster | T1 \| T2 \| ... |prod(caster
| | T1 & T2 & ...` |