Presi
Presi (short for praesidium, Latin meaning protection or guard) is a libary
that lets you build interfaces and get out of the box runtime type checking
and JSON deserialization. Presi was inspired by DRY, prop-types, and Scala
class objects to let you only define an interface once but still allow you to:
- Use the defined interface to statically type check
objects in your code,
- Check the type of arbitrary objects that come from
unsafe IO sources (e.g. user input).
How to Install
npm install --save presi
How to Use
import {I, Z} from 'presi';
When you need to define an interface, i.e.
interface User {
name: string;
age: number;
}
instead do
class User extends I({
name: Z.string,
age: Z.number,
}) {}
-
User
is the interface with a string, name
, and a number, age
.
-
I
is a mixin which creates type for User
and attaches the deserialization
function.
From there you can use User
like a regular interface. But additionally, you
can use new User(your unknown object)
which creates a User
object if given
valid data or throws if not.
const user1: User = { name: 'A', age: 1 };
const user2: User = { name: 1, age: 1 };
const user3: User = { name: 'A' };
const data = {
name: 100,
age: 1,
}
const user4 = new User(data);
In essence,
class _ extends I({
becomes a substitute for
interface _ {
Z
Z, which stands for deserializer, is a set of 1 and 2 arity functions that
either check that it's argument is a primative or, when given a type spec,
checks that it's argument follows that spec.
import {G, I, Z} from 'presi';
class ObjectDef extends I({
stringValue: Z.string,
numberValue: Z.number,
booleanValue: Z.boolean,
literalKeyValue: Z.literal('Key'),
literal100Value: Z.literal(100),
optionalStringValue: Z.optional(Z.string),
optionalLiteralPValue: Z.o(Z.literal('P')),
arrayOfNumbers: Z.array(Z.number),
tupleNumNum: Z.tuple([Z.number, Z.number]),
nestedObject: Z.object({ z: Z.Object({z: Z.optional(Z.string) }) }),
stringOrNumber: Z.oneOf(Z.string, Z.number),
numberOrNull: Z.oneOf(Z.number, Z.null),
tripleTuple: Z.tuple([Z.string, Z.number, Z.array(Z.string)]),
}) {}
class objectComposition extends I{
objectDef: ObjectDef._,
}
Project Goals
- Structure once philosophy.
- Nearly free deserialization.
- Can take output from JSON.parse.
- Run time type checking.
- Usable types in TypeScript for compile time type checking.
Technical Notes
- Classes give free structure, type, and function.
- "Structure once" means the means of deserialization needs incorporated in the
declaration.
Limitations
- Due to converting a user created interface to generic then back again,
extraneous keys will not be type checked.
- Currently does not support reflection.