Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

typend

eveble1.8kMIT1.1.3TypeScript support: included

Runtime validation for TypeScript

eveble, typend, simplecheck, check, meteor, variable, instanceof, instance, evaluation, matcher, match, typescript, runtime, validator, validation

readme

banner

Runtime validation for TypeScript

Typend allows for runtime validation, conversion & reflection of TypeScript declarations and is can be used as building block for any DDD(Domain Driven Design) focused framework or similar architectures.

It was built for as part of CQRS framework Eveble - check it out!


Always wanted a runtime validation that implements TypeScript's declarations as expectations?

import { check } from 'typend';
// Constructors
check<any>('anything');
check<string>('foo');
check<number>(1337);
check<boolean>(true);
check<null>(null);
check<undefined>(undefined);
check<void>(undefined);
check<never>(undefined);
check<Record<any, any>>({});
check<string[]>(['foo']);
check<[string, number]>(['foo', 1337]);
check<Date>(new Date('December 17, 1995 03:24:00'));
// Literals
check<'foo'>('foo');
check<1337>(1337);
check<true>(true);
check<false>(false);
check<{ key: string }>({ key: 'foo' });
check<['foo', 1337]>(['foo', 1337]);

Interfaces?

import { check } from 'typend';

interface Person {
  firstName: string;
  lastName: string;
  height: number;
}

check<Person>({ firstName: 'Jane', lastName: 'Don', height: 175 });

Runtime on-construction class validation?

import { expect } from 'chai';
import { define, check, UnequalValueError, PropsOf } from 'typend';

@define()
class Unicorn {
  sentence: 'sparkle';

  constructor(sentence: 'sparkle') {
    check<PropsOf<Unicorn>>({sentence});
    this.sentence = sentence;
  }
}
expect(() => new Unicorn('🦄🦄 Charrlieee! 🍌👑').to.throw(
  UnequalValueError
);

Existing classes?

import { define, check } from 'typend';

@define()
class MyClass {
  key: string;

  constructor(key: string) {
    this.key = key;
  }
}
const myClass = new MyClass('my-string');

expect(check<MyClass>(myClass)).to.be.true;
expect(check<$TypeOf<MyClass>>(myClass)).to.be.true;

Custom types not provided by TypeScript:

import { check, integer } from 'typend';

check<integer>(10);

Reflecting interfaces or other types(classes included!) to native-a-like forms?

import { expect } from 'chai';

interface Person {
  firstName: string;
  lastName: string;
  height: number;
  getName(): string;
}

const PersonInterface = reflect<Person>();
expect(PersonInterface).to.be.instanceof(Object);
expect(PersonInterface).to.be.eql({
  firstName: String,
  lastName: String,
  height: Number,
  getName: Function,
});

Converting interfaces or other types(classes included!) to validable forms?

import { expect } from 'chai';
import { convert, PropTypes, Interface } from 'typend';

interface Person {
  firstName: string;
  lastName: string;
  height: number;
  getName(): string;
}

const PersonInterface = convert<Person>();
expect(PersonInterface).to.be.instanceof(Interface);
expect(PersonInterface).to.be.eql({
  firstName: PropTypes.instanceOf(String),
  lastName: PropTypes.instanceOf(String),
  height: PropTypes.instanceOf(Number),
  getName: PropTypes.instanceOf(Function),
});

HTW?(How the f***?)

This package uses tsruntime done by Vadym Holoveichuk@goloveychuk as a base to evaluate kind's of types.

Typend is an experimental package that should be used as toolbox. Package exposes all internal components so most of them can be replaced or be used as part of building blocks for creating frameworks or other packages.

Requirements

Installation

  1. To use typend with your app:
npm install typend tsruntime ttypescript reflect-metadata

or

yarn add typend tsruntime ttypescript reflect-metadata
  1. Add new tsconfig.json or change existing one:
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "plugins": [
      {
        "transform": "tsruntime/dist/transform/transformer.js",
        "type": "program"
      }
    ]
  }
}
  1. Run ttypescript with compiler:
ts-node

Use arguments:

ts-node --compiler=ttypescript src/index.ts

or

cross-env TS_NODE_COMPILER=\"ttypescript\" ts-node --project ./tsconfig.json src/index.ts
rollup.js
  1. Install dependencies:
npm i --save-dev rollup rollup-plugin-commonjs rollup-plugin-filesize rollup-plugin-json rollup-plugin-node-resolve rollup-plugin-sourcemaps rollup-plugin-typescript2 rimraf cross-env
  1. Add/change rollup.config.js to resemble:
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import filesize from 'rollup-plugin-filesize';
import typescript from 'rollup-plugin-typescript2';
import json from 'rollup-plugin-json';

import sourceMaps from 'rollup-plugin-sourcemaps';

const env = process.env.NODE_ENV;
const pkg = require('./package.json');

export default {
  input: 'src/index.ts',
  output: {
    file: {
      es: pkg.module,
      cjs: pkg.main,
    }[env],
    format: env,
  },
  external: [
    ...Object.keys(pkg.dependencies || {}),
    ...Object.keys(pkg.peerDependencies || {}),
  ],
  plugins: [
    resolve(),
    json(),
    commonjs(),
    filesize(),
    typescript({
      typescript: require('typescript'),
    }),
    sourceMaps(),
  ],
};
  1. Add scripts to package.json:
{
  "scripts": {
    "build:cjs": "./node_modules/.bin/cross-env NODE_ENV=cjs rollup -c",
    "build:es": "./node_modules/.bin/cross-env NODE_ENV=es rollup -c",
    "build": "npm run clean && npm run build:es && npm run build:cjs",
    "clean": "./node_modules/.bin/rimraf dist"
  }
}

If you have problems with setting up compilation environment - try using our eveble-boilerplate as a template.

Documentation

Learn more about typend at https://eveble.github.io/typend/ .

Caveats

Please be aware that this is experimental module and using it has some drawbacks:

  1. Compilation time will be increased(its less visible on more modern computer builds).
  2. Making changes to referenced types will be not reflected real-time in testing environment in watch mode. Tests need to be rerunned again(this includes types defined in separate, dedicated file also).
  3. Not every declaration of TypeScript generic type will work for validation.
  4. We did our best to flush out most applicable architecture for this concept, however API can be subjected to change upon valid reasons.

Under the hood

Typend uses tsruntime for type reflection on validation with TypeScript declaration.

End-user API functions like: check, is, instanceOf, validate, isValid, isInstanceOf use exposed Typend class instance.

With this in mind - as developer you are able to replace or extend parts of the Typend that implements Library interface.

Testing

Using yarn:

yarn test

License

MIT

changelog

1.1.3 (2023-04-09)

Bug Fixes

1.1.2 (2023-04-09)

Bug Fixes

1.1.1 (2021-05-08)

Bug Fixes

1.1.0 (2020-10-18)

Features

  • patterns: add LocaleString (ab4a63d)
  • validators: add LocaleStringValidator (ff9706c)

1.0.2 (2020-07-12)

Bug Fixes

  • validators: optional expectation on tuple (dfa51fb)

1.0.1 (2020-07-02)

Bug Fixes

  • remove leftovers from boilerplate setup (629d9a1)

1.0.0 (2020-07-02)

Bug Fixes

  • exports (d7f25a6)
  • Integer export lowercased (d79ef04)
  • linting (b7f217b)
  • replacing parts of described OneOf expectation (b58469c)
  • returning Collection instead of Interface on PropTypes.shape (cb64ad7)
  • throwing error on validation of unequal value or tuple length (873480d)
  • use of lowercase PropTypes.integer on test (dd4769f)
  • class-converter: issue with nested objects (46fef0d)
  • docs: add hidden tag to fix error while rendering on Docusaurus (8d580ba)
  • docs: building file paths on subdirectories (a5df359)
  • docs: normalize interface title and sidebar_label property (512fd06)
  • validation: add support for validation of patterns like Integer (19cad52)
  • constant naming (ba30b72)
  • issue with optional arrays on object (682c53e)
  • types (08420d0)
  • eslint: disable next line with no-unused-vars (de94fa5)
  • ensure that native types are described properly (55e068e)
  • error order (c40b7bc)

Features

  • add support for flagging patterns as optional (bca670c)
  • add support for flagging patterns as required (230d60b)
  • add Typend (99e38dd)
  • add Utility (3fd9997)
  • add utility types for validation mimicking TypeScript’s Utility Types (1c0b245)
  • converters: add ArrayConverter (cbc7b40)
  • converters: add ClassConverter (ec412c3)
  • converters: add FunctionConverter (9af4cba)
  • converters: add LiteralConverter (c4c7891)
  • converters: add NativeConverter (612444f)
  • converters: add NilConverter (8633acf)
  • converters: add ObjectConverter (ff082f8)
  • converters: add PrimitiveConverter (197eb19)
  • converters: add TSRuntimeConverter (12ea4c7)
  • utilities: add PropsOf utility (325eac1)
  • utilities: add TypeOf utility (4c725bf)
  • add Validator (62b7b4f)
  • converters: add PropsOfConverter (e8e9520)
  • converters: add ReferenceConverter (c8562ba)
  • converters: add TupleConverter (cefc639)
  • converters: add TypeOfConverter (d92677d)
  • converters: add UnionConverter (68b0f97)
  • converters: add UnknownConverter (df5897f)
  • converters: add UnrecognizedConverter (2d14c65)
  • patterns: add Any pattern (1527ba7)
  • patterns: add Class pattern (8a8e473)
  • patterns: add Collection pattern (3fc4f2d)
  • patterns: add CollectionIncluding pattern (c4c187d)
  • patterns: add CollectionWithin pattern (faa2a13)
  • patterns: add Equals pattern (07a7893)
  • patterns: add InstanceOf pattern (ba39b14)
  • patterns: add Integer pattern (9f4e139)
  • patterns: add Interface pattern (4f928aa)
  • patterns: add Internal pattern (66cce0e)
  • patterns: add List pattern (a61b120)
  • patterns: add Maybe pattern (c8d549a)
  • patterns: add Never pattern (04ab944)
  • patterns: add OneOf pattern (b86713b)
  • patterns: add Optional pattern (bf68a92)
  • patterns: add Tuple pattern (149026a)
  • patterns: add Unknown pattern (b69733a)
  • patterns: add Unrecognized pattern (7c82944)
  • patterns: add Void pattern (0b41b37)
  • patterns: add Where pattern (ef5dc1c)
  • patterns: add WrapperPattern (e0c8db4)
  • transformers: add InjectingPropsTransformer (4b23102)
  • transformers: add InternalPropsTransformer (0e654d7)
  • validators: add AnyValidator (d6637c0)
  • validators: add ClassValidator (fd1efbc)
  • validators: add CollectionIncludingValidator (9413691)
  • validators: add CollectionValidator (0b16baf)
  • validators: add CollectionWithinValidator (f4c486d)
  • validators: add EqualsValidator (6c5e823)
  • validators: add InstanceOfValidator (7852d4f)
  • validators: add IntegerValidator (31d5492)
  • validators: add InterfaceValidator (7b75bcb)
  • validators: add InternalValidator (4b26266)
  • validators: add ListValidator (d84e822)
  • validators: add MaybeValidator (0e228cd)
  • validators: add NeverValidator (dbac60b)
  • validators: add OneOfValidator (f98fdc7)
  • validators: add OptionalValidator (a0918d8)
  • validators: add PatternValidator (8c427f7)
  • validators: add TupleValidator (a179e1d)
  • validators: add UnknownValidator (1dada22)
  • validators: add UnrecognizedValidator (3373bd6)
  • validators: add VoidValidator (79c4cca)
  • validators: add WhereValidator (342dd93)
  • add define decorator (8ff9356)
  • add Describer (6a3afa9)
  • add Description (0cf3773)
  • add helpers (245ab56)
  • add internal annotation (b49551d)
  • add literal keys (6083fb9)
  • add metadata keys (3fce30b)
  • add Pattern (75158cb)
  • add types (2c5d227)
  • add validable annotation (5cc6229)