TypeScriptToLua Transpiler
TypeScriptToLua (tstl) is a transpiler that converts TypeScript code into Lua. It enables developers to leverage TypeScript's static typing, tooling (like ESLint, Prettier, and VS Code support), and maintainability benefits for projects targeting Lua environments. The current stable version is 1.34.0, and new versions are released regularly, often mirroring TypeScript's own release cadence of roughly every 3 months for major updates, with patch releases as needed. A key differentiator is its ability to generate Lua code compatible with various Lua versions, including a 'universal' target, and its extensive use of TypeScript's type information to produce optimized and portable Lua. It's particularly useful for game development (e.g., Dota 2, Defold, LÖVE 2D, World of Warcraft addons) or any application where Lua scripting is used, allowing for strong type safety and improved development workflows through declaration files for existing Lua APIs.
Common errors
-
Error: TS5023: Unknown compiler option 'luaTarget'.
cause The `tstl` specific options are not correctly nested within the `tstl` block in `tsconfig.json` or the `tsconfig.json` schema is not being recognized.fixEnsure `luaTarget` and other `tstl` options are inside a `"tstl": {}` object in your `tsconfig.json`. Example: `{ "compilerOptions": { ... }, "tstl": { "luaTarget": "universal" } }`. Ensure your IDE is using the correct schema by adding `"$schema": "https://raw.githubusercontent.com/TypeScriptToLua/TypeScriptToLua/master/tsconfig-schema.json"` -
Error: Cannot find module 'typescript-to-lua' or its corresponding type declarations.
cause The `typescript-to-lua` package is not installed, or `typescript` (its peer dependency) is missing, or `node_modules` are not properly resolved.fixRun `npm install -D typescript typescript-to-lua` to ensure both the transpiler and its peer TypeScript dependency are installed. If issues persist, try `rm -rf node_modules && npm install`. -
Runtime Error: attempt to call a nil value (global 'console')
cause The transpiled Lua code is attempting to access a global object like `console` which exists in browser/Node.js environments but not inherently in a Lua runtime. `typescript-to-lua` does not automatically polyfill all browser/Node.js globals.fixProvide Lua-specific implementations or declarations for global objects and functions you use (e.g., `console.log` could map to Lua's `print`). Use TypeScript declaration files (`.d.ts`) to inform the transpiler about these Lua-native APIs. For instance, declare `declare function print(...args: any[]): void;` and map `console.log` to `print`.
Warnings
- breaking Breaking changes frequently occur with TypeScript version upgrades. For example, `typescript-to-lua` v1.10.0 required TypeScript 4.8 and changed how language extensions are distributed, moving from `"typescript-to-lua/..."` to `"types": ["@typescript-to-lua/language-extensions"]` in `tsconfig.json`. Always review the `CHANGELOG.md` when upgrading `typescript-to-lua` or `typescript` versions.
- breaking The default `luaTarget` was changed to `"universal"` in version 0.34.0. If you were implicitly relying on `LuaJIT` as the default target, you must now explicitly set `"luaTarget": "JIT"` in your `tsconfig.json` file.
- gotcha TypeScriptToLua converts `null` and `undefined` to Lua's `nil`. While often interchangeable in TypeScript, they are distinct concepts in JavaScript. It is recommended to prefer `undefined` over `null` in `tstl` codebases to better represent the transpiled Lua and align with TypeScript idioms.
- gotcha Lua has a limit of 200 local variables within a single function. Large TypeScriptToLua programs with many imports or extensively large functions can hit this limit at runtime, leading to crashes that the transpiler does not catch at compile time. Each import statement typically creates two local variables in Lua.
- gotcha Behavioral differences exist for some JavaScript features in Lua. For example, JavaScript's loose equality (`==`) and strict equality (`===`) are both translated to strict equality in Lua. Array `length` behavior and `Array.sort` stability also differ from JavaScript.
- gotcha Some standard TypeScript compiler options, such as `outFile`, `importHelpers`, `target` (should always be `esnext`), and `module` (should be omitted or default to `ES2015`), are either ignored or require specific values for `typescript-to-lua` to function correctly. Additionally, `composite`, `build.incremental`, and `emitDecoratorMetadata` are not supported.
Install
-
npm install typescript-to-lua -
yarn add typescript-to-lua -
pnpm add typescript-to-lua
Imports
- transpileProject
const { transpileProject } = require('typescript-to-lua');import { transpileProject } from 'typescript-to-lua'; - transpileString
import * as tstl from 'typescript-to-lua'; const result = tstl.transpileString(...);
import { transpileString } from 'typescript-to-lua'; - LuaTarget
import { LuaTarget } from 'typescript-to-lua'; - CompilerOptions
import { CompilerOptions } from 'typescript-to-lua';import type { CompilerOptions } from 'typescript-to-lua';
Quickstart
{
"compilerOptions": {
"target": "esnext",
"lib": ["esnext"],
"strict": true,
"moduleResolution": "node",
"rootDir": ".",
"outDir": "./dist"
},
"tstl": {
"luaTarget": "universal",
"luaLibImport": "require"
},
"include": ["src/**/*.ts"]
}
// src/main.ts
function greet(name: string): string {
return `Hello, ${name}!`;
}
console.log(greet("TypeScriptToLua"));
// package.json (excerpt)
/*
{
"name": "my-lua-project",
"version": "1.0.0",
"devDependencies": {
"typescript": "^5.0.0",
"typescript-to-lua": "^1.34.0"
},
"scripts": {
"build": "npx tstl"
}
}
*/