Tish vs JavaScript

What differs from JavaScript and what is additional in Tish.

This page documents how Tish differs from JavaScript and what Tish adds. Since Tish is not pure JS, developers coming from JS/TS need this reference.

Differences from JavaScript

TopicJavaScriptTish
Undefinedundefined existsnull only
typeof null"object""null" (Tish has no undefined, so null is the absence-of-value type)
Equality== (loose) and ====== / !== only; no coercion
Variable declarationvar, let, constlet, const only (no var)
Function keywordfunctionfn (or function)
Destructuring parametersfunction f({ a }) {}, (({ x }) => x)Supported (Rust / interpreter / JS compile); bytecode-backed runtimes require a single arg + let destructure in the body
Block syntaxBraces requiredOptional braces (indentation)
thisthis keywordNo this; use explicit parameters
PrototypesPrototype chainPlain objects only
Optional chainingReturns undefinedReturns null
Other omissionsclass, super, delete, instanceof, for..in, generators, Symbol, BigInt, Map, SetNot in Tish

Additions (Tish-specific)

FeatureDescription
fn keywordShorthand for function
Indentation blocksTab/space for blocks instead of {}
Optional type annotationsParsed, not enforced (gradual typing)
Feature flagshttp, fs, process, regex — secure-by-default
serve(port, handler)Built-in HTTP server (no Express)
fetch / fetchAllHTTP client APIs (return Promise; await fetch(...) for the response; response body is a byte ReadableStream, not a string — use getReader() or await res.text() / await res.json())
Promise, setTimeout, setInterval, clearTimeout, clearIntervalECMA-style Promises and non-blocking timers (with http feature)
async fn / awaitAsync functions and await expressions
readFile / writeFile / etc.File system APIs (feature-gated)
new expressionsParsed and lowered on every backend; semantics are not full ECMA [[Construct]] on VM, interpreter, and native Rust (see below). tish build --target js emits real JavaScript new.
import / exportModules for builtins (http, etc.), native tish:* specs (Rust native backend), and multi-file resolution where the toolchain supports it — not arbitrary npm package graphs on all targets (see below).
Interpreter + native compileSame source runs both ways

Semantic Details

No undefined

Tish has only null. Optional chaining (?.) and missing properties return null where JavaScript returns undefined. Because of this, typeof null returns "null" in Tish, unlike JavaScript where it returns "object".

Strict equality only

Loose equality (==) is not supported. Use === and !== only. There is no implicit type coercion in comparisons.

No this, with, eval

Tish omits these for security and compileability. Pass explicit parameters instead of relying on this.

No prototypes

Objects and arrays are plain data structures. No Object.create, prototype chain, or instanceof.

No classes or super

There is no class syntax and no super. Use plain objects and functions.

new expressions (limited)

Tish accepts new (including argument lists and spread) like JavaScript syntax, but without class there are no user-defined class constructors in the JS sense. On the VM, interpreter, and native Rust output, construction uses a host construct path (roughly: call a plain function value with the args, or an object constructor exposed via an internal __construct hook), not full ECMA [[Construct]] — no this binding, no prototype wiring, and still no instanceof. Some builtins are approximations (for example, new Uint8Array(n) may yield a numeric array of zeros rather than a real typed byte buffer; some globals like AudioContext are stubs). The interpreter may accept new on a slightly wider set of builtin values than the VM; if you need identical behavior, test your target. With tish build --target js, emitted code uses the engine’s real new (wrapped with ?? null for Tish’s null rules).

Modules (import / export)

Tish supports import and export for language builtins (e.g. import { serve } from 'http' with the http feature), native module specs such as tish:fs, tish:http, tish:process, tish:ws, etc. on the Rust native compile path, and multi-file programs where the resolver is enabled. tish:* and npm-linked native modules require tish build --native-backend rust (not the Cranelift/LLVM “embedded bytecode only” binary paths). This is not “every npm package on every target”; dynamic import() / import.meta are out of scope for ECMA alignment in the same way as in the main Tish docs.

Async/await support

Tish supports async fn and await for asynchronous I/O. Use await fetch(...) and await fetchAll(...) for HTTP (both return Promises). Promises (ECMA-262 Promise objects) are supported: Promise(executor), .then, .catch, .finally, Promise.resolve, Promise.reject, Promise.all, Promise.race. Host APIs setTimeout, setInterval, clearTimeout, and clearInterval are non-blocking (callbacks run after the delay; setTimeout returns immediately). Generators are not supported.

See also

Improve this documentation