The TJS Language

Why TJS exists, the rules it will not bend, the reference for its declarations and syntax, and the design notes behind the harder decisions. This part assumes you already write JavaScript. The worked examples live elsewhere, in TJS Interactive Examples and its Basics, Patterns and Advanced sections; this part is where you look things up and find out why they are the way they are.

Where to start depends on you:

What a TJS signature tells you

The goal of this part is that you can read a signature like this one and say exactly what it accepts, what it returns, and what it checks at runtime:

function greet(name: 'Alice', times = 1): 'Hello, Alice!' {
  return `Hello, ${name}${'!'.repeat(times)}`
}

console.log(greet('Bob'))     // Hello, Bob!
console.log(greet('Bob', 3))  // Hello, Bob!!!

// A wrong argument is a returned error, not a crash.
const result = greet(42)
console.log(isMonadicError(result))             // true
console.log(result.expected, result.actual)     // string number
console.log(isMonadicError(greet('Bob', 1.5)))  // true: times must be an integer

The value after a colon is an example: name is a required string, and 'Alice' is one such string. (If you know TypeScript: this is not a literal type, and name accepts any string.) Every call checks name at runtime.

times = 1 is an optional parameter that defaults to 1. Its default is also its example, and 1 is written without a decimal point, so times accepts only integers; 1.0 would accept any number. When a caller passes times, it is checked on that call too, which is why greet('Bob', 1.5) is refused.

The return annotation is a worked example. When the file is transpiled (by tjs check, the command-line checker, or by a build), TJS calls greet with the parameter examples, name = 'Alice' and times = 1, and the result must equal 'Hello, Alice!'. If it does not, the file fails to transpile. With a plain : the return value is not checked again on later calls; write :? for that, or :! for a return type with no test.

Calling greet(42) does not throw. It returns an error value, a MonadicError, that says what was expected and what arrived; isMonadicError(x) is the way to test for one.

Each of these rules has a section in the syntax reference: parameters and defaults, return annotations and errors.

How to read this part

The chapters fall into three tiers: the argument for TJS, the reference you look things up in, and the design notes you open when a question about why comes up.

The argument

The reference

The design notes

These are for readers who want to know why a decision went the way it did, or who are about to change one. None of them is needed to write TJS. Each is marked with where it stands, because a design note and a description of shipped behaviour read alike.

Note Status
Type identity Current: a map of how TJS checks types today, kept honest by a test
Runtime fusion Shipped for TJS's error type; the same rule decides what else is shared
North star: JSON-Schema + predicates Direction: where the type system is heading, possibly after 1.0
FunctionPredicate: Design Notes Partly shipped: checks only that a value is a function
Case study: fixing switch Shipped: given exists; switch keeps its fall-through, with a warning
Small scoped parsers, not a rewrite Partly shipped: colon disambiguation is built, expression extent is not
Ambient Contracts Exploratory: a design idea with experimental spikes, not built
Native Engine Integration Exploratory: what native V8 or JavaScriptCore support could unlock

All chapters in order