Introduction

Start here. TypeScript's types vanish when it compiles, so data that arrives while the program runs (an API response, parsed JSON, a form field) is never checked against them. A string parameter that receives 42 goes on as if nothing were wrong. TJS keeps the types in the compiled program and can check them on every call.

From TypeScript to JavaScript, by way of TJS

The converter, fromTS, turns TypeScript into TJS, and TJS is then compiled to JavaScript. On the command line it is tjs convert (tjs convert --emit-tjs file.ts prints the TJS in between); on this site it runs for you on every TypeScript example.

Here is a TypeScript function and the TJS the converter writes for it:

// TypeScript
function greet(names: string[], excited?: boolean): string {
  return `Hello, ${names.join(' and ')}${excited ? '!' : ''}`
}

// TJS, from fromTS
function greet(names: [string], excited: boolean | undefined):! string {
  return `Hello, ${names.join(' and ')}${excited ? '!' : ''}`
}

Three spellings changed, and the body did not:

names: [string] and :! string are kept in the output as metadata: they document the function and are available for checking. Keeping a type is not the same as checking it.

Checking is a separate switch

By default a converted file is faithful: it behaves exactly as the compiled TypeScript did at runtime, so converting a working program cannot break it. The types are carried along, and nothing checks them. Called with 42 instead of an array, the faithful greet above fails the way the original would, with TypeError: names.join is not a function.

One comment at the top of the file switches checking on:

/* @tjs TjsStrict */

TjsStrict opts the file into full TJS, and every parameter type the converter kept becomes a check that runs on every call. Called with 42, the checked greet does not throw. It returns a MonadicError, a value naming the parameter, the type it expected and what it got, without running its body:

MonadicError: Expected array of string for '<source>:2:greet.names', got number

TypeScript Examples explains what to do with that value. A check costs time on each call, in proportion to the shape being checked: unnoticeable in a function that does real work, measurable in a tiny one called in a hot loop. The TJS Performance Guide has the numbers and the way to skip a check.

The examples