Examples

Runnable programs from the examples/showcase/ folder. Compile with lumen compile <file>.ts, or run tests with lumen test.

inventory.ts enums · interfaces · record arrays · for…of · template literals

enum Category { Food, Tool, Book }

interface Item {
  name: string;
  price: int;
  category: Category;
}

function describe(item: Item): string {
  return `${item.name}: $${item.price}`;
}

let items: Item[] = [
  { name: "apple", price: 2, category: Category.Food },
  { name: "hammer", price: 15, category: Category.Tool },
  { name: "novel", price: 9, category: Category.Book },
];

let total = 0;
for (const item of items) {
  console.log(describe(item));
  total += item.price;
}
console.log(`total: $${total}`);

higher-order.ts function values · arrow functions · ternary

function applyTwice(f: (n: int) => int, v: int): int {
  return f(f(v));
}

function triple(x: int): int {
  return x * 3;
}

console.log(applyTwice(triple, 2));               // 18
console.log(applyTwice((x: int) => x + 10, 5));   // 25

let clamp: (n: int) => int = (x: int) => x > 100 ? 100 : x;
console.log(clamp(250));   // 100
console.log(clamp(42));    // 42

config.ts optional fields · ?? · null-narrowing · defer

interface Settings {
  host: string;
  port?: int;
}

function connect(s: Settings): void {
  using _ = defer(() => console.log("connection closed"));
  let port = s.port ?? 8080;
  console.log(`connecting to ${s.host}:${port}`);
}

function label(name: string | null): string {
  if (name != null) {
    return name;
  }
  return "anonymous";
}

connect({ host: "localhost" });                  // :8080  + closed
connect({ host: "api.example.com", port: 443 }); // :443   + closed
console.log(label("ada"));                        // ada
console.log(label(null));                         // anonymous

math.test.ts test blocks · expect, run with lumen test

function gcd(a: int, b: int): int {
  let x = a;
  let y = b;
  while (y != 0) {
    let t = y;
    y = x % y;
    x = t;
  }
  return x;
}

test "gcd computes greatest common divisor" {
  expect(gcd(12, 8) == 4);
  expect(gcd(17, 5) == 1);
}

ffi-math.ts declare functions · linking libm, lumen compile

// @link m
declare function pow(base: number, exp: number): number;
declare 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

url-imports.ts import from a URL · fetched and inlined at compile time

// The .ts is fetched over HTTPS at compile time and inlined into the build --
// no package manager, no install step. A package is just a URL.
import greet from "https://lumen-lang.org/package/std-contrib/hello/hello.ts";

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

pipeline.ts array methods · map · filter · reduce · join

let nums: int[] = [1, 2, 3, 4, 5, 6];

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

console.log(doubled.join(", "));   // 4, 8, 12
console.log(total);                // 24

strings.ts string methods · split · toUpperCase · includes · for…of

let csv = "ada,grace,linus";
let names = csv.split(",");

for (const name of names) {
  console.log(name.toUpperCase());   // ADA / GRACE / LINUS
}

console.log(names.length);                       // 3
console.log("grace,hopper".includes("grace"));   // true

generics.ts generic function · generic class · type arguments

function firstOf<T>(xs: T[]): T {
  return xs[0];
}

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

console.log(firstOf<int>([10, 20, 30]));      // 10
console.log(firstOf<string>(["a", "b"]));     // a

let boxed = new Box<string>("hello");
console.log(boxed.get());                     // hello

shapes.ts discriminated union · type alias · switch on tag

type Circle = { kind: "circle", radius: int };
type Square = { kind: "square", side: int };
type Shape = Circle | Square;

function area(s: Shape): int {
  switch (s.kind) {
    case "circle":
      return s.radius * s.radius * 3;
    case "square":
      return s.side * s.side;
  }
  return 0;
}

console.log(area({ kind: "circle", radius: 4 }));   // 48
console.log(area({ kind: "square", side: 5 }));     // 25

inherit.ts classes · extends · super · method override

class Animal {
  protected name: string;
  constructor(name: string) {
    this.name = name;
  }
  speak(): string {
    return this.name + " makes a sound";
  }
}

class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }
  speak(): string {
    return super.speak() + " (woof)";
  }
}

let a = new Animal("Cat");
let d = new Dog("Rex");
console.log(a.speak());   // Cat makes a sound
console.log(d.speak());   // Rex makes a sound (woof)

errors.ts error handling · throw · try / catch / finally

try {
  console.log("parsing");
  throw Error("empty port");
  console.log("unreached");
} catch (e) {
  console.log("caught");
  console.log(e.message);
} finally {
  console.log("done");
}
// parsing
// caught
// empty port
// done

collections.ts Map · Set · typed keys and values

let scores: Map<string, int> = new Map<string, int>();
scores.set("ada", 90);
scores.set("linus", 85);
scores.set("ada", 95);

console.log(scores.size);          // 2
console.log(scores.get("ada"));    // 95
console.log(scores.has("linus"));  // true

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

varargs.ts rest parameters · spread call · default params

function sum(...nums: int[]): int {
  let total: int = 0;
  for (const n of nums) {
    total = total + n;
  }
  return total;
}

function greet(name: string, greeting: string = "Hello"): string {
  return greeting + ", " + name;
}

let extra: int[] = [4, 5, 6];
console.log(sum(1, 2, 3));          // 6
console.log(sum(1, ...extra));      // 16
console.log(greet("World"));        // Hello, World
console.log(greet("World", "Hi"));  // Hi, World

async.ts async / await · Promise, runs on a native event loop

async function fetchBase(): Promise<int> {
  return 10;
}

async function total(n: int): Promise<int> {
  let base: int = await fetchBase();
  return base + n;
}

console.log(await fetchBase());   // 10
console.log(await total(5));      // 15
console.log(await total(32));     // 42

quickjs.ts embed a JavaScript sandbox via FFI · community package

// The quickjs package runs JavaScript inside a native Lumen binary and passes
// values both ways. It links a C library, so it is built locally.
import { open, close, setInt, evalNumber, getString } from "./quickjs.ts";

open();
using _ = defer(() => close());

setInt("base", 21);
console.log(evalNumber("base * 2 + Math.sqrt(16)"));   // 46

evalNumber("globalThis.greeting = 'hi ' + base");
console.log(getString("greeting"));                    // hi 21

wordstats.ts a real CLI · args · fs.readFileSync · Map · Set · classes

// A command-line tool: counts words in a file and prints the most frequent.
// Build with `lumen compile wordstats.ts`, then run `./wordstats sample.txt`.
let text = fs.readFileSync(arg(1), "utf8");

let counts: Map<string, int> = new Map<string, int>();
let word = "";
for (const ch of text.toLowerCase().split("")) {
  let code = ch.charCodeAt(0);
  let isLetter = code >= 97 && code <= 122;
  if (isLetter) {
    word = word + ch;
  } else if (word != "") {
    counts.set(word, (counts.get(word) ?? 0) + 1);
    word = "";
  }
}

console.log(`unique words: ${counts.size}`);

sqlite.ts talk to SQLite over FFI · links libsqlite3 · built locally

// A typed wrapper over SQLite through the C FFI. A small C shim hides the
// library's out-pointers behind plain functions; the pragmas below link it.
// @link ./sqlite_shim.o
// @link /opt/homebrew/opt/sqlite/lib/libsqlite3.dylib
declare function db_open(path: string): int;
declare function db_exec(sql: string): int;
declare function db_query_int(sql: string): int;
declare function db_query_text(sql: string): string;

db_open(":memory:");
db_exec("CREATE TABLE books (title TEXT, year INT)");
db_exec("INSERT INTO books VALUES ('Crafting Interpreters', 2021)");

console.log(db_query_int("SELECT COUNT(*) FROM books"));               // 1
console.log(db_query_text("SELECT title FROM books LIMIT 1"));         // Crafting Interpreters