ts-cast
v0.1.3
Published
Runtime typechecking
Downloads
511
Readme
ts-cast ·
Runtime 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
andValidation
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.
const Person = struct({ name: string, age: integer });
type Person = ReturnType<typeof Person>;
// the same as
type Person = { name: string, age: number };
Installation
npm i ts-cast
Documentation
Read ts-cast
documentation on github:
https://github.com/DScheglov/ts-cast/tree/master/docs
Getting Started
Let's start with an example:
./src/schema.ts
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<typeof Person>;
export type TCoords = ReturnType<typeof Coords>;
export type TBook = ReturnType<typeof Book>;
Then we can use defined types and their caster
-s in this way:
./src/index.ts
import { Person, TPerson, Book, TBook } from './schema';
const me = Person({ name: "John Smith", email: "[email protected]" });
const meAgain: TPerson = {
name: "John Smith",
email: "[email protected]", // 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: '[email protected]' },
],
coords: [1.2, 23.32]
}, "myBook");
const book: TBook = myBook;
console.dir(book, { depth: null });
TypeScript Analogy
Primitive Types
| ts-cast | TypeScript |
| :-------: | :---------: |
| number
| number
|
| integer
| number
|
| string
| string
|
| boolean
| boolean
|
| nil
| null
|
| undef
| undefined
|
Example:
import { integer } from 'ts-cast';
const x = integer(10); // works
const y = integer(Math.PI); // throws TypeError
const z = integet('10'); // also throws TypeError
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
Literal Types
| 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
|
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
Complex Types
| ts-cast | TypeScript |
| :--------------------------------------: | :-------------: |
| tuple(caster<T1>, caster<T2>, ...)
| [T1, T2, ...]
|
| array(caster<T>)
| T[]
|
| struct({ a: caster<A>, b: caster<B> })
| { a: A, b: B } |
| record(caster<K>, caster<V>)
| Record<K, V>
|
Type Modifiers
| ts-cast | TypeScript |
| :-----------------------: | :--------------: |
| caster<T>.optional
| T \| undefined
|
| caster<T>.default(v)
| x: T = v
|
| caster<T>.nullable
| T \| null
|
| caster<T>.restrict(...)
| T
|
Operations over Types
| ts-cast | TypeScript |
| :----------------------------------: | :---------------: |
| union(caster<T1>, caster<T2>, ...)
| T1 \| T2 \| ...
|
| prod(caster<T1>, caster<T2>, ...)
| T1 & T2 & ...
|