npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

typend

v1.1.3

Published

Runtime validation for TypeScript

Downloads

67

Readme


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