Skip to content

Modules and imports ​

Every .tks file is a module. Share code between files with export and import, using the same syntax as TypeScript.

Exporting ​

ts
// src/combat/damage.tks
export const CRIT_MULTIPLIER: int = 2;

export function damage(base: int, crit: boolean): int {
    return crit ? base * CRIT_MULTIPLIER : base;
}

export default class Dice {
    static label(sides: int): string {
        return "d" + sides;
    }
}

Importing ​

ts
// src/main.tks
import Dice, { damage } from "./combat/damage";

console.log(damage(5, true));
console.log(Dice.label(20));

Relative paths start with ./ or ../. The .tks extension is optional. A path that names a folder loads that folder's index.tks.

All the usual forms work:

ts
import { damage, CRIT_MULTIPLIER } from "./combat/damage";   // named
import { damage as hit } from "./combat/damage";             // renamed
import Dice from "./combat/damage";                          // default
import * as combat from "./combat/damage";                   // namespace
import type { Enemy } from "./enemy";                        // types only
import "./setup";                                            // run for side effects

And on the export side, export { a, b as c }, export { x } from "./other" and export * from "./other" re-export from another module.

Each module runs once, the first time it is imported. Circular imports are allowed: classes and functions can refer to each other across the cycle.

System modules ​

Some modules are built into thicket. You import them by name:

ts
import { Files } from "fs";
import { Http } from "http";
import { Sprite } from "willow";

Each one exports a class you call directly, like Files.readText(path) or Http.get(url).

KindNames
Always availablefs, env, events, reactivity
Listed in systemsaudio, bitmap, compress, crypto, database, http, net, ws, shell
Host moduleswillow

fs also carries the path helpers, such as Files.join and Files.dirname. There is no separate path module.

The everyday names, like console, Math, JSON, print, sleep and the error classes, need no import at all. The same goes for System (the platform, arguments, System.exit), and in a window app engine, App, Keyboard, Mouse and Gamepad.

systems and permissions ​

A project's thicket.json can list the systems it uses:

json5
{
    entry: "src/main.tks",
    systems: ["http", "willow"],
    permissions: { net: true, fs: true },
}
  • No systems key means every system the host has.
  • A list is strict. Importing a listable system that is not on the list is an error, with a hint to add it.
  • Permissions are separate. A system says "include this code". A permission says "allow it at run time". The first call that needs a permission you have not granted throws a PermissionError naming the fix. The permissions are fs, net, crypto, database, shell, env and audio, all off by default. async worker functions need no permission: a worker is pure computation and gets no I/O modules. The checker rejects an imported I/O binding used in a worker.

Path aliases ​

Long relative paths get old fast. compiler.paths in thicket.json defines shortcuts:

json5
{
    entry: "src/main.tks",
    compiler: { paths: { "@combat/*": "src/combat/*" } },
}
ts
import { CRIT_MULTIPLIER } from "@combat/damage";
console.log(CRIT_MULTIPLIER);

Packages ​

Code from another folder, a git repository or a zip is a package. You import it by name, just like a system. See Packages.