Type Annotations

Optional, gradually-checked TypeScript-style type annotations in Tish.

Tish supports optional TypeScript-style type annotations. They're gradual: omit them and a binding is dynamic; add them and you get an opt-in compile-time checker plus faster native code. On their own, annotations never change runtime behavior.

Syntax

// Variable declarations
let x: number = 42
const name: string = "hello"
let arr: number[] = [1, 2, 3]
 
// Function parameters and return types
fn add(a: number, b: number): number {
    return a + b
}
 
// Object types
let person: { name: string, age: number } = { name: "Alice", age: 30 }
 
// Union and optional (T? === T | null)
let value: number | string = 42
let maybe: number? = null
 
// Rest parameters
fn sum(...args: number[]): number { ... }

Supported Types

TypeDescription
numberNumeric values (f64)
stringString values
booleantrue or false
nullThe null value
voidNo return value (functions)
T[] / Array<T>Array of T (Array<T> desugars to T[])
T?Optional — shorthand for T | null
{ k: T }Object with typed properties
T | UUnion (either T or U)
T & UIntersection (both T and U)
[T, U]Tuple — fixed length, positional
"on" | "off"Literal types (and unions of them)
(a: T) => RFunction type
<T>Generics on fn, type, and interface
interface Name { … }Named structural type (supports extends)
x as TType assertion (cast)
// Generics, interfaces, tuples, literals, intersections, casts
fn identity<T>(x: T): T { return x }
type Box<T> = { value: T }
interface Point { x: number, y: number }
interface Dog extends Animal { bark: boolean }
type Person = Named & Aged
type Status = "on" | "off"
let pair: [number, string] = [7, "z"]
let n = (42 as number) + 8

Type checking (--check)

A gradual checker verifies annotations at build time. It is opt-in and conservative — it reports only mismatches it can prove (zero false positives), so unannotated code stays fully dynamic.

tish build app.tish --check warn    # report diagnostics, keep building
tish build app.tish --check error   # report AND fail the build (exit 1)
tish type warning: 2:17: Type 'number' is not assignable to type 'string'.

Set TISH_CHECK=warn (or error) to make it the default for a project, and gate CI on --check error. The checker resolves type aliases, arrays, and object/interface shapes; it does not yet narrow literal-union membership or perform full TypeScript inference.

Native codegen

With --native-backend rust, annotations lower to native Rust types — number → f64, string → String, boolean → bool, number[] → Vec<f64>, and Box<number> monomorphizes to a struct with an f64 field — with no Value boxing. An inference pass also propagates these types through arithmetic, loop counters, and homogeneous arrays, so much idiomatic numeric code goes native without any explicit annotations. See Native backend.

Notes

  • Annotations are optional; omitting them is equivalent to dynamic typing.
  • They do not change evaluation by themselves — enforcement is the opt-in --check pass, not a runtime cost.
  • Generic type parameters are erased for checking (gradual) but specialized in native codegen.

Improve this documentation