Code Monkey home page Code Monkey logo

ts-runtime's Introduction

Build Status Coverage Status

ts-runtime

A package for generating runtime type checks from TypeScript type annotations for JavaScript, using the TypeScript compiler API.

Please note, that this package is still experimental and resulting code is not intended to be used in production. It is a proof of concept for adding runtime type checks by making use of the recently published TypeScript transformation API. Feel free to report bugs and to make suggestions. Pull requests are also very welcome.

Playground

You can try ts-runtime on the playground: https://fabiandev.github.io/ts-runtime/

Quick Start

$ yarn global add ts-runtime
$ tsr --help

You can also use npm -g install ts-runtime.

Credits

Type reflections and assertions for the runtime environment are being made possible by flow-runtime, a runtime type system for JavaScript.

Transformations

Most of explicit type annotations will be reflected (and checked) at runtime. Checks for implicitly inferred types may be added in a future release. In the following section the most important cases are documented.

Source File

On top of every source file, the runtime type checking library is imported.

import t from 'ts-runtime/lib';

Variables

It will be distinguished between reassignable declarations (var and let) and constant declarations (const).

Reassignable Declarations

A variable declaration that may be reassigned at runtime as the following:

let num: number;
num = "Hello World!";

will be reflected and checked as shown below:

let _numType = t.number(), num;
num = _numType.assert("Hello World!")

Constant Declarations

A constant declaration does only need to be checked when declared, and no additional variable holding the variable's type, has to be introduced.

const num: number = "Hello World!";

The const declaration from above, results in:

const num = t.number().assert("Hello World!");

Assertions

In TypeScript the above assignments would already be flagged by the compiler. By using the type assertion as any, any assignment will be allowed but still caught at runtime with this package.

true as any as number;

The above assertion may not be a real world example, but there are situations where similar things happen. Imagine calling a function, that returns any. While you know that the returned value will be a number, you also want the TypeScript compiler to be aware of it and you assert it as number. Probably this function call is from an external library and a bug is introduced that a boolean value is returned instead, which will remain unnoticed unless checked at runtime:

t.number().assert(true);

Functions

Function parameters and its return value will be checked as well, and functions will be annotated to extract its type reflection at runtime.

Function Declarations

This function simply creates a number from a string.

function getNumberFromString(str: string): number {
  return Number(str);
}

The code below is the result, with runtime type checks inserted.

function getNumberFromString(str) {
  let _strType = t.string();
  const _returnType = t.return(t.number());
  t.param("str", _strType).assert(str);
  return _returnType.assert(Number(str));
}

By default the function is also annotated, to get the type reflection of the object at runtime with type queries:

t.annotate(getNumberFromString, t.function(t.param("str", t.string()), t.return(t.number())));

Annotations can be turned off, by setting the annotate option to false or using the --noAnnotate flag with the CLI.

Function Expressions

Also function expressions will be transformed:

const getNumberFromString = function(str: string): number {
  return Number(str);
}

This declaration will be converted to:

const getNumberFromString = function (str) {
  let _strType = t.string();
  const _returnType = t.return(t.number());
  t.param("str", _strType).assert(str);
  return _returnType.assert(Number(str));
};

Again, by default the function is annotated like so:

const getNumberFromString = t.annotate(function (str) {
  // function body
}, t.function(t.param("str", t.string()), t.return(t.number())));

Arrow Functions

Arrow function are also supported, with a similar result to function expressions. If runtime checks have to be inserted into an arrow function without a body, ts-runtime generates it for you:

const getNumberFromString = (str: string): number => Number(str);

This one-liner is great, but in order to assert the values it is transformed to the following:

const getNumberFromString = (str) => {
  let _strType = t.string();
  const _returnType = t.return(t.number());
  t.param("str", _strType).assert(str);
  return _returnType.assert(Number(str));
};

Of course, also arrow functions are annotated by default:

const getNumberFromString = t.annotate((str) => {
  // arrow function body
}, t.function(t.param("str", t.string()), t.return(t.number())));

Type Queries

In the following example, TypeScript gets the type of a variable and uses it as type for another variable declaration.

let num = 10;
let numType: typeof num = "Hello World!";

In ts-runtime this will be transformed to:

let num = 10;
let _myNumType = t.typeOf(num), myNum = _myNumType.assert("Hello World!");

Please note, that num is not reflected and asserted, because it lacks an explicit type annotation.

Enums

The TypeScript compiler option preserveConstEnums will be always set to true by ts-runtime. A warning in the console will let you know.

Enum Declarations

enum Action {
  None,
  Save,
  Update
}

The enum from above will be transformed to the following by TypeScript:

var Action;
(function (Action) {
  Action[Action["None"] = 0] = "None";
  Action[Action["Save"] = 1] = "Save";
  Action[Action["Update"] = 2] = "Update";
})(Action || (Action = {}));

and annotated by ts-runtime with the reflection below:

t.annotate(Action, t.enum(t.enumMember(0), t.enumMember(1), t.enumMember(2)));

Enum References

When using the enum as a type reference, only the numbers 0, 1, and 2 can be assigned to action:

let action: Action;
let _actionType = t.enumRef(Action), action;

The same is true when using a specific enum members as reference. In this example only the number 1 can be assigned to saveAction:

let saveAction: Action.Save;
let _saveActionType = t.enumMember(Action.Save), saveAction;

Type Aliases

Type aliases are removed entirely by the TypeScript compiler.

type MyType = {
  property: string;
  optional?: number;
  method: (param: boolean) => void;
}

The type alias declaration from above will be replaced with the following reflection:

const MyType = t.type("MyType", t.object(
  t.property("property", t.string()),
  t.property("optional", t.number(), true),
  t.property("method", t.function(t.param("param", t.boolean()), t.return(t.void())))
));

Self references are supported.

Interfaces

Also interfaces would be compiled away.

interface BaseInterface {
  [index: string]: any;
}

interface MyInterface extends BaseInterface {
  prop: string;
}

With ts-runtime they will be replaced with a reflection:

const BaseInterface = t.type("BaseInterface", t.object(
  t.indexer("index", t.string(), t.any()))
);

const MyInterface = t.type("MyInterface", t.intersect(t.ref(BaseInterface), t.object(
  t.property("prop", t.string())
)));

Classes

Classes are transformed with support for properties, static properties, static and non-static methods, deriving from other classes (extends), implementing interfaces (implements), as well as method overloading.

class MyClass {
  method(param?: number): void {

  }
}

At this point, only a very minimal class transformation, with a single method, is shown:

class MyClass {
  method(param) {
    let _paramType = t.number();
    const _returnType = t.return(t.void());
    t.param("param", _paramType, true).assert(param);
  }
}

By default also classes are annotated:

@t.annotate(t.class("MyClass", 
  t.property("method", t.function(t.param("param", t.number(), true), t.return(t.void())))
))
class MyClass {
  // class body
}

Overloading

Method overloading is supported for type aliases, interfaces and classes, and generates union types based on the overloads.

class MyInterface {
  method(param: number): string;
  method(param: boolean): string;
  method(param: any): any {
    // implementation
  }
}

While all overloads are considered (excluding merged declarations) when generating a reflection, the implementation itself is ignored:

@t.annotate(t.class("MyInterface",
  t.property("method", t.function(
    t.param("param", t.union(t.number(), t.boolean())), t.return(t.string()))
  )
))
class MyInterface {
  method(param) {
    // implementation
  }
}

Generics

Generics are supported for functions, classes, interfaces and type aliases.

function asArray<T>(val: T): T[] {
  return [val];
}

The above snippet shows a simple function that makes use of generics to specify the return type, which results in the following transformation:

function asArray(val) {
  const T = t.typeParameter("T");
  let _valType = t.flowInto(T);
  const _returnType = t.return(t.array(T));
  t.param("val", _valType).assert(val);
  return _returnType.assert([val]);
}

Externals and Ambient Declarations

We were seeing a couple of different transformations based on local variables. What about external packages, declaration files and ambient declarations? They are collected and emitted to a single file.

Externals

Imagine the following type reference:

import * as ts from 'typescript';
let flowNode: ts.FlowNode;

It points to the interface FlowNode inside typescript.d.ts:

interface FlowNode {
  flags: FlowFlags;
  id?: number;
}

The reference is removed and replaced by a string. This string holds the fully qualified name of the reference, and the hashed file name as a suffix, to prevent naming clashes:

let _flowNodeType = t.ref("ts.FlowNode.82613696"), flowNode;

The actual reflections go into a single file (tsr-declaration.js by default):

t.declare(t.type("ts.FlowFlags.82613696", t.enum(/* enum members */)));
t.declare(t.type("ts.FlowNode.82613696", t.object(/* properties */)));

By default declarations from built in libs (such as DOM, or ES6) are not reflected, but inferred at runtime.

Declarations

Also local declarations will be included in tsr-declarations.js:

declare module MyModule {
  class MyClass {

  }
}

The code from above will be reflected as follows:

t.declare(t.class("MyModule.MyClass.3446180452", t.object()));

The generated file will be located in the common directory of all entry files or in the root of outDir or outFile. For some controls regarding this file, have a look at the options.

Limitations

  • Only as number syntax for type assertions (no angle-bracket syntax: <number>).
  • No reflection of mapped types, indexed access types and type operators yet.
  • readonly is currently only checked for classes.
  • Class visibility modifiers are not asserted.
  • Class type parameters are only checked when extending, at this time.
  • Types with self references and generics are not asserted correctly.
  • No class expressions (const A = class { }), only class declarations (class A { }) can be used.
  • ExpressionWithTypeArguments can only contain PropertyAccessExpressions as expression with an Identifier as name, recursively.
  • No JSX support.

Options

noAnnotate

Type: boolean
Default: false

Specifies if classes and function should be annotated.

compilerOptions

Type: ts.CompilerOptions
Default:

{
  moduleResolution: ts.ModuleResolutionKind.NodeJs,
  module: ts.ModuleKind.ES2015,
  target: ts.ScriptTarget.ES2015,
  lib: ["lib.es2015.d.ts"],
  strictNullChecks: true,
  experimentalDecorators: true,
  sourceMap: false,
  removeComments: true,
  preserveConstEnums: true,
}

The option preserveConstEnum will always be set to true by ts-runtime.

declarationFileName

Type: string
Default: "tsr-declarations"

The file name where all external and ambient declarations will be written to. Excludes a path or an extension.

excludeDeclarationFile

Type: boolean
Default: false

Specifies if the generated file should be imported on top of every entry file.

excludeLib

Type: boolean
Default: false

Specifies if the library import on top of every file should be omitted.

force

Type: boolean
Default: false

Try to continue if TypeScript compiler diagnostics occurred.

keepTemp

Type: boolean
Default: false

Do not delete temporary files on finish.

tempFolderName

Type: string
Default: ".tsr"

Name of the directory, where temporary files should be written to.

libNamespace

Type: string
Default: ""

Prefix for the default library import.

libIdentifier

Type: string
Default: "t"

Identifier of the default library import, prefixed by its namespace. Looks like the following by default

import t from "ts-runtime/lib";

libIdentifier

Type: boolean
Default: false

By default, built in libraries, such as DOM or ES6, are not reflected, but inferred at runtime.

declarationPrefix

Type: string
Default: "_"

If new variables are introduced while transforming, they will be prefixed with this specified string.

moduleAlias

Type: boolean
Default: false

Adds import "module-alias/register"; on top of every file.

stackTraceOutput

Type: number
Default: 3

Limit the output of the stack trace. This only takes effect when using the CLI.

log

Type: boolean
Default: true

Log messages to the console. This option is not available via the CLI.

API

It is easy to make use of ts-runtime via Node.js. entryFiles is a string[] and an Options object may optionally be passed as a second parameter.

import { transform } from 'ts-runtime';
transform(entryFiles);

It is also possible to listen for various events:

import { transform, bus } from 'ts-runtime';

bus.on(bus.events.START, () => {
  // callback if processing is about to start
});

transform(entryFiles, { log: false });

CLI

  Usage: tsr <file...> [options]

  ---------  ts-runtime  ---------
  Turns TypeScript type assertions
  into runtime type checks for you
  --------------------------------

  Options:

    -h, --help                               output usage information
    -v, --version                            output the version number
    -a, --noAnnotate                         do not annotate classes and functions
    -c, --tsConfig <path>                    use the compiler options of the given tsconfig.json
    -C, --compilerOptions <compilerOptions>  set TypeScript compiler options. defaults to "{}"
    -d, --declarationFileName <fileName>     set file name for global declarations. defaults to "tsr-declarations"
    -e, --excludeDeclarationFile             do not automatically import ambient declarations in the entry file. default to false
    -E, --excludeLib                         do not automatically import the runtime library. defaults to false
    -f, --force                              try to finish on TypeScript compiler error. defaults to false
    -F, --fast                               no fancy status for the command line, but faster processing. defaults to false
    -l, --libIdentifier <name>               lib import name. defaults to "t"
    -L, --libDeclarations                    reflect declarations from global libs (e.g. DOM). defaults to false
    -m, --moduleAlias                        import package module-alias on top of every file.
    -n, --libNamespace <namespace>           prefix for lib and code additions. defaults to ""
    -p, --declarationPrefix <namespace>      prefix for added variables. defaults to "_"
    -s, --stackTraceOutput <limit>           output a specified number of lines of the stack trace. defaults to 3

  Examples:

    $ tsr entry.ts --force
    $ tsr src/entry1 bin/entry2 lib/entry3
    $ tsr entry.ts -c tsconfig.json

Building

$ git checkout https://github.com/fabiandev/ts-runtime.git
$ cd ts-runtime
$ yarn build

ts-runtime's People

Contributors

fabiandev avatar superelement avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ts-runtime's Issues

Unable to Generate d.ts Declaration Files

Demo project: https://github.com/cryptokat/ts-runtime-issue/

Hash.d.ts file is missing due to the error of TS4070 and TS4052

yarn build-tsr --force
yarn run v1.5.1
$ yarn tsr Hash.ts -c tsconfig.json --force
ℹ ts-runtime v0.1.35
✔ Processing (184ms)
✔ Scanning (13ms)
✔ Transforming (14ms)
✖ Hash.ts(5,31): error TS4070: Parameter 'input' of public static method from exported class has or is using private name 'Uint8Array'.
✖ Hash.ts(5,44): error TS4052: Return type of public static method from exported class has or is using private name 'Uint8Array'.
✔ Emitting (287ms)
✔ Done in 498ms, but there were 2 compiler diagnostics.
Done in 1.29s.

Problematic Code

export default class Hash {
    public static h256(input : Uint8Array) : Uint8Array {
        return new Uint8Array(0);
    }
}

Normal Code

export default class Hash {
    private h256(input : Uint8Array) : Uint8Array {
        return new Uint8Array(0);
    }
}
export default class Hash {
    public static h256(input : string) : string {
        return "";
    }
}

disallow NaN for number types

How about an option to throw when NaN is assigned to a number type?
Right now this library allows things like const x: number = parseFloat("hello");

...which makes sense as default behaviour because typeof NaN === "number" in JavaScript, but it'd be useful to be able to use this library to do things like safely parse values in a querystring, coming from a redis cache, etc. etc.

So could it be another cli option or something?

Bug: tsr-declarations requires do not work with rootDir

If I give a rootDir, and ask tsr to transpile a file that is not from the root directory, it assumes the tsr-declaration.js path incorrectly:
e.g.

tsr --tsConfig tsconfig.json src/types/assert.ts

will give the error

$ node lib/types/assert.js
Error: Cannot find module './tsr-declarations'

I think the core of this error is ts-runtime assumes I will always be generating runtime check files at the root of my repo. However, I just want runtime checks on a few functions in my repo that deal with user input.

tsconfig.json:

{
  "compilerOptions": {
    "rootDir": "./src",
    "outDir": "./lib/"
  },
  "include": ["src/**/*.ts"]
}

let me know if you want a reproducible repo, I can push one!

Can this work that way c# reflection works?

It is possible to to extend each javascript object with a getType() method that them lets me reflect over the property names and methods.

If you give an idea where to start, I will create a branch and get to work

Custom Type Run time type checking issue not working

I have a use case where I want to ensure my custom types are respected during run time as well. I would have written custom checks myself but Typescript's String Literal Types are not available during run time.

I am posting my code sample and generated code with ts-runtime library -

My Code -

type UploadMediaPayload = {
    abc: string
}

type analyticsEvent = {
  'Upload Media': UploadMediaPayload
}

function sampleFunction<Key extends keyof analyticsEvent>(evtName: Key, evtData: analyticsEvent[Key]){
    console.log(evtName, evtData);
}

const getData = () =>
  Promise.resolve({
      key: "key",
      value: "value"
  });
 
// usage (1)
getData()
  .then(data => {
    const {key, value} = data;
    sampleFunction(<keyof analyticsEvent>key, <UploadMediaPayload><unknown>value);
  });

getData();

sampleFunction("Upload Media", {abc: "abc"});
let key, value;
sampleFunction(key, value);

Generated Code

import t from "ts-runtime/lib";
const UploadMediaPayload = t.type("UploadMediaPayload", t.object(t.property("abc", t.string())));
const analyticsEvent = t.type("analyticsEvent", t.object(t.property("pload Medi", t.ref(UploadMediaPayload))));
function sampleFunction(evtName, evtData) {
    const Key = t.typeParameter("Key", t.any());
    let _evtNameType = t.flowInto(Key);
    let _evtDataType = t.any();
    t.param("evtName", _evtNameType).assert(evtName);
    t.param("evtData", _evtDataType).assert(evtData);
    console.log(evtName, evtData);
}
t.annotate(sampleFunction, t.function(fn => {
    const Key = fn.typeParameter("Key", t.any());
    return [t.param("evtName", t.flowInto(Key)), t.param("evtData", t.any()), t.return(t.any())];
}));
const getData = t.annotate(() => {
    return Promise.resolve({
        key: "key",
        value: "value"
    });
}, t.function(t.return(t.any())));
// usage (1)
getData()
    .then(t.annotate((data) => {
    const { key, value } = data;
    sampleFunction(key, value);
}, t.function(t.param("data", t.any()), t.return(t.any()))));
getData();
sampleFunction("Upload Media", { abc: "abc" });
let key, value;
sampleFunction(key, value);

analyticsEvent is not referred in the generated code. What do I have to make it work ?

Might this be picked up again?

This project seems pretty dead, but I don't see why there isn't any community will to work on it. Flow-runtime is the only reason my company is stuck on Flow instead of TypeScript; there's really just no TypeScript equivalent except this, and runtime checks can be essential for verifying API responses.

I'd probably be willing to help! I just don't know that I have time to do the whole thing myself.

Fails with compilerOptions.noEmitOnError=true

Considering simple test.ts file and tsconfig.json like the following:

console.log('it works')
{
  "compilerOptions": {
    "noEmitOnError": true
  }
}

I am able to compile using tsr src/test.ts :

ℹ ts-runtime v0.1.35
✔ Processing (3s)
✔ Scanning (29ms)
✔ Transforming (18ms)
✔ Emitting (82ms)
✔ Done in 2s 819ms.

But not with compilerOptions.noEmitOnError=true using tsr -c tsconfig.json src/test.ts

ℹ ts-runtime v0.1.35
✔ Processing (3s)
✔ Scanning (27ms)
✔ Transforming (18ms)
✖ error TS6053: File '/home/thomas/.nvm/versions/node/v10.0.0/lib/node_modules/ts-runtime/node_modules/typescript/lib/lib.d.ts' not found.
✖ error TS2318: Cannot find global type 'Array'.
✖ error TS2318: Cannot find global type 'Boolean'.
✖ error TS2318: Cannot find global type 'Function'.
✖ error TS2318: Cannot find global type 'IArguments'.
✖ error TS2318: Cannot find global type 'Number'.
✖ error TS2318: Cannot find global type 'Object'.
✖ error TS2318: Cannot find global type 'RegExp'.
✖ error TS2318: Cannot find global type 'String'.
✖ src/test.ts(1,15): error TS2307: Cannot find module 'ts-runtime/lib'.
✖ src/test.ts(2,1): error TS2304: Cannot find name 'console'.
✖ Emitting was interrupted.

lib.d.ts exists at this location ([email protected])
If noEmitOnError is set to false, it works again.

Local type-check

Is it possible to use this library to do local type checks? I don't want to type check my whole app at runtime (I trust TypeScript to do that at compile time), but I'd like to type check individual variables at certain places (mainly API boundaries). So for example this:

verify<MyType>(obj); // throws if obj doesn't conform to interface MyType

This is obviously supported by this tool, because it does it behind the scenes, but I wonder if this API is exposed?

Some issues with generic classes

Slick library! One issue with generic classes though.

class Foo {}
class GenericClass <FOO extends Foo> {}
class Implementation extends GenericClass <Foo> {}

is compiled to Javascript with the following line:

Implementation[t.TypeParametersSymbol] = _ImplementationTypeParametersSymbol;

which references the undefined _ImplementationTypeParametersSymbol and causes a runtime error.

Full compiled output:

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import t from "ts-runtime/lib";
let Foo = class Foo {
};
Foo = __decorate([
    t.annotate(t.class("Foo", t.object()))
], Foo);
const _GenericClassTypeParametersSymbol = Symbol("GenericClassTypeParameters");
let GenericClass = class GenericClass {
    constructor() {
        const _typeParameters = {
            FOO: t.typeParameter("FOO", t.ref(Foo))
        };
        this[_GenericClassTypeParametersSymbol] = _typeParameters;
    }
};
GenericClass[t.TypeParametersSymbol] = _GenericClassTypeParametersSymbol;
GenericClass = __decorate([
    t.annotate(t.class("GenericClass", GenericClass => {
        const FOO = GenericClass.typeParameter("FOO", t.ref(Foo));
        return [];
    }))
], GenericClass);
let Implementation = class Implementation extends GenericClass {
    constructor(...args) {
        super(...args);
        t.bindTypeParameters(this, t.ref(Foo));
    }
};
Implementation[t.TypeParametersSymbol] = _ImplementationTypeParametersSymbol;
Implementation = __decorate([
    t.annotate(t.class("Implementation", t.extends(t.ref(GenericClass, t.ref(Foo)))))
], Implementation);

SourceMap support?

Currently there seems no sourceMap support. The line numbers in the runtime errors are actually those in the compiled .js files.

How to use it with React Native?

Hello, i would like to use your library with my React Native apps, but i don't understand how to change default typescript runtime on your tsr runtime. Maybe do you know how to do it?

Webpack plugin

Nice work @fabiandev; I'm really excited to test this out at some point!

Anyway, just throwing this idea out there in case you or anyone else have time for it at some point: a webpack plugin to automatically handle inserting the import into each source file and building with tsr.

In addition to making it a lot simpler to get started by piggybacking on existing tooling, this would abstract away most of the work required for integrations like angular/angular-cli#6763 (at least for non-prod builds; some extra work might be needed to integrate tsr into Angular's AOT compiler).

[Curious] Design

I'm curious; what do you think of a Babel plugin that would transpile this:

type Todo = {
  userId: number;
  id: number;
  title: string;
  completed: boolean;
}

const resp = await fetch("https://jsonplaceholder.typicode.com/todos/1");

const data = await resp.json();

assert(data typeof Todo);

to that:

const __TodoType = {
  userId: Number;
  id: Number;
  title: String;
  completed: Boolean;
};
const __isTodoType = obj => (
  obj &&
  obj.constructor === Object &&
  Object.keys(obj).length === Object.keys(__TodoType).length &&
  Object.entries(obj)
    .every(([prop, val]) =>
      __TodoType[prop] && val &&
      __TodoType[prop] === val.constructor)
);

const resp = await fetch("https://jsonplaceholder.typicode.com/todos/1");

const data = await resp.json();

assert(__isTodoType(data));

Not finding Promise

This library seems very exciting! I just started using it and it seems to think that Promise is a private name:

tsr -c tsconfig.json  passit_sdk/*
ℹ ts-runtime v0.1.23
✔ Processing (1s)
✔ Scanning (750ms)
✔ Transforming (505ms)
✖ passit_sdk/api.ts(45,51): error TS4055: Return type of public method from exported class has or is using private name 'Promise'.
...

My tsconfig.js that I am using is

{
  "compilerOptions": {
    "target": "es5",
    "experimentalDecorators": true,
    "sourceMap": true,
    "module": "commonjs",
    "declaration": true,
    "removeComments": true,
    "types" : [ "node", "jasmine", "core-js" ],
    "outDir": "./js",
    "lib": ["es2015", "dom"]
  },
  "exclude": [
    "node_modules",
    "js"
  ]
}

Any ideas?

Feature Request: transform() input and output strings

Following up the discussion of #5, I have looked over instructions on building a loader, and I should be able to build a simple webpack loader that transforms certain files into runtime check files. Basically, the webpack loader will compile certain ts files with ts-runtime into javascript, then those files will be passed through ts-loader or awesome-typescript-loader as normal.

To make this work however, I need transform() to be able to take in a string and output a string or buffer. Webpack expects each loader to act this way, it is how we are able to chain loaders together. Is a change like this possible?

No reflection for syntax kind 'UnknownKeyword' found.

I'm having an issue that production js contains phisical folder names for runtime-interfaces output.
I'm on version 0.1.35

Once I switch on 0.2.0 it generates error. It will generate the error even if I comment out the content of the source ts file

node node_modules/ts-runtime/bin/index.js src/app/glb/ts/runtime-interfaces.ts

i ts-runtime v0.2.0
√ Processing (1s)
√ Scanning (22ms)
√ Transforming (28ms)
× No reflection for syntax kind 'UnknownKeyword' found.
× Emitting was interrupted.

Runtime type system with io-ts

Currently flow-runtime is being used as a runtime type system. In a next step create an interface to exchange the underlying library, e.g., to io-ts, which was developed with TypeScript in mind and seems to be more lightweigh.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.