Write TypeScript.
Compile to a native binary.

Lumen type‑checks familiar TypeScript syntax and compiles it straight to a small, dependency‑free executable. No VM, no garbage collector, no runtime.

curl -fsSL https://lumen-lang.org/install.sh | sh
// Call libm directly -- no bindings, no runtime.
// @link m
extern function sqrt(x: number): number;

function hypot(a: number, b: number): number {
  defer console.log("computed");   // runs at scope exit
  return sqrt(a * a + b * b);
}

console.log(hypot(3.0, 4.0));   // computed → 5

Hello, Lumen

Familiar syntax, fixed static types, no runtime — just a native executable.

interface Point {
  x: int;
  y: int;
}

function distanceSq(a: Point, b: Point): int {
  let dx = a.x - b.x;
  let dy = a.y - b.y;
  return dx * dx + dy * dy;
}

let origin: Point = { x: 0, y: 0 };
let p: Point = { x: 3, y: 4 };
console.log(`distance² = ${distanceSq(origin, p)}`);  // distance² = 25

What's in the language

A predictable static subset of TypeScript — no prototypes, no eval, no dynamic shapes.

Static types

Local inference, int/i64/number/bool/string, float & hex/binary literals.

Records & interfaces

Closed object shapes, nested records, arrays of records, enums.

Full control flow

if/else if, while, do, C‑style for, for…of, switch, ternary.

Null safety

T | null, optional ? fields, ??, ?., and if (x != null) narrowing.

First-class functions

Function types, arrow functions, and capturing closures.

Classes & inheritance

extends, super, public/private/protected, static, readonly, and get/set.

Template literals

`hi ${name}` with string & numeric interpolation.

defer

Scope‑exit cleanup, last‑in‑first‑out.

Built-in tests

test "…" { expect(…); } run with lumen test.

C FFI

extern function + // @link call native C libraries — scalars and strings marshal across the boundary.

String methods

split, slice, trim, includes, indexOf, replace, repeat, padStart, toUpperCase, and more.

Array methods

map, filter, reduce, forEach, find, some, every, includes, indexOf, join.

Generics

Generic functions, classes, and interfaces with Array<T> — monomorphized at compile time, no boxing.

Type aliases & unions

type aliases, discriminated unions narrowed by a literal tag, and as assertions.

Error handling

try/catch/finally and throw, with a readable .message on the caught error.

Maps, Sets & tuples

Map<K, V>, Set<T>, and fixed-shape tuple types like [int, string].

async / await

async functions return Promise<T> and await resolves them on a fast native event loop.

Flexible parameters

Default values, rest parameters, and spread — checked statically, no arguments object.

URL imports

Import a default export from a relative file or an https:// URL — a package is just a URL.

Native output

Compiles to a small, fast, dependency‑free native binary.

Closures that compile

Capture locals by value — lowered to a heap environment, no GC.

function makeAdder(n: int): (x: int) => int {
  return (x: int) => x + n;
}

let add10 = makeAdder(10);
console.log(add10(5));   // 15

let factor = 3;
let nums: int[] = [1, 2, 3];
for (const v of nums) {
  console.log((v: int) => v * factor);  // closes over `factor`
}

Classes

Fields, a constructor, this, and methods — instances are heap structs.

class Counter {
  count: int;
  constructor(start: int) {
    this.count = start;
  }
  increment(): void {
    this.count += 1;
  }
  get(): int {
    return this.count;
  }
}

let c = new Counter(5);
c.increment();
console.log(c.get());   // 6

Methods on strings and arrays

The familiar collection and string methods, statically typed and compiled.

let nums: int[] = [1, 2, 3, 4, 5];
let doubled = nums.map((n: int) => n * 2);
let evens = nums.filter((n: int) => n % 2 == 0);
let total = nums.reduce((acc: int, n: int) => acc + n, 0);

console.log(doubled.join(", "));   // 2, 4, 6, 8, 10
console.log(evens.join(", "));     // 2, 4
console.log(total);                // 15

let s = "  Hello, World  ";
console.log(s.trim().toUpperCase());   // HELLO, WORLD
console.log(s.trim().split(", ")[1]);  // World

Generics, monomorphized

Write once over a type parameter; each instantiation compiles to specialized code — no boxing.

function identity<T>(x: T): T {
  return x;
}

class Box<T> {
  value: T;
  constructor(v: T) {
    this.value = v;
  }
  get(): T {
    return this.value;
  }
}

console.log(identity<int>(42));      // 42
console.log(identity<string>("hi"));  // hi
let b = new Box<int>(7);
console.log(b.get());                 // 7

Maps, Sets, and tuples

Typed keyed collections and fixed-shape tuples, with the methods you expect.

let counts: Map<string, int> = new Map<string, int>();
counts.set("apples", 3);
counts.set("pears", 5);
console.log(counts.get("apples"));   // 3
console.log(counts.has("pears"));    // true

let tags: Set<string> = new Set<string>();
tags.add("red");
tags.add("red");
tags.add("blue");
console.log(tags.size);   // 2

let pair: [string, int] = ["age", 30];
console.log(pair[0]);   // age
console.log(pair[1]);   // 30

async / await

Async functions return a Promise<T>; await resolves it on a fast native event loop.

async function fetchValue(n: int): Promise<int> {
  return n * 2;
}

async function total(): Promise<int> {
  let a: int = await fetchValue(10);
  let b: int = await fetchValue(11);
  return a + b;
}

console.log(await total());   // 42

Errors with try / catch / finally

Throw an error, catch it with a readable message, and run cleanup on every path.

function checkAge(n: int): void {
  try {
    if (n < 0) {
      throw Error("age cannot be negative");
    }
    console.log("age ok");
  } catch (e) {
    console.log("error: " + e.message);
  } finally {
    console.log("checked");
  }
}

checkAge(30);   // age ok / checked
checkAge(-1);   // error: age cannot be negative / checked

Call native libraries

Declare an extern function and link a C library — no bindings generator, no runtime.

// @link m
extern function pow(base: number, exp: number): number;
extern function sqrt(x: number): number;

let hypotSq = pow(3.0, 2.0) + pow(4.0, 2.0);
console.log(sqrt(hypotSq));   // 5
console.log(pow(2.0, 10.0));  // 1024

C++ through an extern "C" shim

Lumen links the C ABI, so expose the C++ you need behind extern "C", then link the object.

// geometry.cpp
extern "C" int rectangle_area(int w, int h) { return w * h; }
// demo.ts
// @link ./geometry.o
extern function rectangle_area(w: int, h: int): int;
console.log(rectangle_area(6, 7));   // 42

Strings across the boundary

Strings marshal too: pass a Lumen string to a C function and copy the returned C string back.

// @link ./shim.o
extern function shout(s: string): string;   // C: const char* shout(const char*)

console.log(shout("hi there"));   // HI THERE

FFI marshals scalars (int, i64, number, bool) and strings. This links local/system libraries — it is not a package manager.

Import from a URL

A package is just a URL. The .ts is fetched over HTTPS and inlined at compile time — no package manager, no install step.

import greet from "https://lumen-lang.org/package/std-contrib/hello/hello.ts";

console.log(greet("world"));   // Hello, world!

A remote module can import its own siblings with relative paths, fetched recursively. The same URL is fetched once per build, and import cycles are reported.

Only https:// is allowed. Remote code runs at build time, so import from sources you trust.

Install

curl -fsSL https://lumen-lang.org/install.sh | sh

Windows: download the .zip from the releases page. Self-contained — no other toolchain required.