tiluaLuau, written the TypeScript way. tilua compiles to Luau and keeps Luau's semantics: the same values, the same
This extension gives you diagnostics, hover, completion, go-to-definition,
find-references, rename, signature help and semantic highlighting for Getting startedInstall the extension, then, in your project:
The extension validates No globals are built in — not
The language, at a glanceEverything not listed here is Luau as you know it: Blocks — braces, and a parenthesised condition
There is no The parentheses around a condition are not decoration: A single statement may stand in for the block, as TypeScript writes it:
Declarations —
|
| Luau | tilua | |
|---|---|---|
| object | { x = 1, y = 2 } |
{ x: 1, y: 2 } |
| array | { 1, 2, 3 } |
[1, 2, 3] |
| computed key | { [k] = v } |
{ [k]: v } |
| shorthand | — | { x, y } |
| spread | — | { ...base, c: 3 }, [...a, ...b] |
Arrays are still Luau arrays underneath — the first element is index 1.
One arrow, for the type and for the function
Luau writes a function type with ->. tilua writes both a function type and
a function value with =>, and decides which from where it stands, since a
type and a value never share a place. -> is gone.
type Reducer = (total: number, value: number) => number
const double = (x: number) => x * 2
const add: Reducer = (a, b) => a + b -- typed by the contract
each(n => print(n)) -- one parameter needs no parens
const wrap = (n: number) => ({ value: n }) -- an object body is parenthesised
An arrow is just a short function expression — there is no second kind of
function — so this inside one is the this of the method around it.
Optionality — no T?
? in type position always belongs to a conditional type, and in expression
position to a ternary or an optional chain. Optionality is TypeScript's:
name?: T -- may be absent; its type is `T | nil`
name: T | nil -- must be written, but may be nil
Omitting an argument requires ? or a default — a parameter typed T | nil
still has to be passed something.
Things Luau does not have at all
- Classes —
class Dog extends Animal { … },constructor,get/set,static,super,new Dog(…), genericclass Box<T>. It is sugar over the usual metatable idiom, andnew Dog(x)isDog.new(x). - Modules —
import/exportinstead ofrequire, includingimport type, re-exports andexport default. Imports are read-only. - Optional chaining —
a?.banda?:m(x), which stop the whole chain when the receiver is nil, and narrow what they tested. - Ternary —
c ? a : b. - Template strings —
`hello ${name}`. - Rest and spread —
...parts: string[]in a signature,f(...names)at a call. Bare...is still Lua's pack. - Array and string methods —
names:filter(…):map(…),text:trim(), written with:as JavaScript writes them with.. Which methods exist comes from the type library, not the language.
A real type system
This is the part that shows up as squiggles. tilua checks what TypeScript checks, not what Luau checks:
strictNullChecksalways on — reading a member of a possibly-nil value is an error until a check narrows the nil away.- TypeScript's narrowing model: references (
x.a.b) rather than just variables, discriminated unions,and/or, early return,break, user type guards (v is T), assertion signatures (asserts v). - Unions, intersections, tuples,
keyof,T[K], conditional types withinfer, mapped types, template literal types, generics with constraints and defaults,satisfies,as const, overload sets, branded types. - Only
nilandfalseare falsy —0and""are truthy, as in Lua, not as in JavaScript.
Three comments switch checking off where you need it, as TypeScript's
// @ts-… do:
--@tilua-nocheck -- before the first line of code: the whole file
--@tilua-ignore -- the next line of code
--@tilua-expect-error -- the next line of code, which must have an error
Full language reference: the
@tilua/parser README.
Settings
| setting | what it does |
|---|---|
tilua.server.path |
absolute path to a cli.js / server.cjs to use instead of the bundled server |
tilua.trace.server |
messages / verbose logs LSP traffic to the tilua output channel |
tilua: Restart Language Server restarts the server without reloading the window.
Other editors
Every feature here is the language server's, so anything you see works the
same anywhere else that speaks LSP. Install
@tilua/language-server,
launch tilua-language-server --stdio (or --node-ipc), and attach it to the
tilua language / .tilua files.
Development
npm install
npm run build
Open this folder in VS Code and press F5. A second window opens on
sample/, with hello.tilua to poke at. After changing the server, rebuild
and run tilua: Restart Language Server in the dev window; to debug the
server itself, run the Attach to server launch configuration (port 6009).
npm run reinstall packages a .vsix and installs it into your own VS Code —
that is also the file to hand someone else. npm run publish publishes to the
Marketplace, which needs a publisher id in package.json and
npx vsce login <publisher-id> once.
src/extension.ts— locate the server, start it, register the restart commandsyntaxes/tilua.tmLanguage.json— TextMate grammar (colours only; the server does the understanding)language-configuration.json— comments, brackets, indentationsample/— the folder the dev host opens