ts2gd
raw JSON → 0.0.36 verified Fri May 01 auth: no javascript
ts2gd is a TypeScript-to-GDScript transpiler for Godot 3.x projects, currently at version 0.0.36. It compiles TypeScript source files directly to GDScript with near-zero runtime overhead and fast incremental compilation (<0.1 seconds after startup). Unlike embedded JavaScript runtimes (e.g., GodotJS), ts2gd outputs native GDScript, ensuring no performance penalty. It enhances developer experience with full TypeScript type safety, autocomplete, and refactoring support. The project is in early beta with occasional breaking changes due to its pre-1.0 status. Development appears active, with updates every few months.
Common errors
error Cannot find name 'KeyList' ↓
cause Enum namespacing; KeyList is not globally scoped
fix
Import KeyList from 'godot':
import { KeyList } from 'godot' error Property '$pressed' does not exist on type 'Button' ↓
cause Signals must be declared in class definition with `$` prefix
fix
If using a built-in signal, ensure the class extends the correct node type; for custom signals, declare
$my_signal!: Signal error Cannot find module 'godot' or its corresponding type declarations ↓
cause Missing generated type definitions; ts2gd --init or compilation hasn't run yet
fix
Run
ts2gd --init to scaffold project and generate types, or run ts2gd --buildOnly to generate @globals.d.ts error TypeError: this.my_rpc_method.rpc is not a function ↓
cause Method is not marked as remote/rpc in GDScript; ts2gd uses `@remote`/`@remotesync` decorator
fix
Add
@remote or @remotesync decorator to the method Warnings
gotcha Scene globals (e.g., MySceneTscn) are automatically created and exported; no need to preload ↓
fix Import the scene global directly (e.g., `import { MySceneTscn } from "godot"`) and use `instance()` instead of `preload()`
gotcha Enums are namespaced under enum name (e.g., `KeyList.KEY_SPACE`), not global scope ↓
fix Use `EnumName.Property` syntax; see generated `@globals.d.ts` for full list
gotcha Signals must be declared as class properties with `$` prefix and type `Signal` ↓
fix Declare `$my_signal!: Signal` (use `!` to avoid TS uninitialized error)
breaking Autoload classes require `@autoload` decorator and an exported instance ↓
fix Add `@autoload` decorator to class, then `export const MyAutoload = new MyAutoloadClass()`
gotcha `rpc` calls use method-chaining syntax: `this.my_rpc_method.rpc("arg")` instead of `this.rpc("my_rpc_method", "arg")` ↓
fix Call `this.methodName.rpc(arg)` instead of `this.rpc("methodName", arg)`
breaking Godot 3.3+ is required for autoload export functionality ↓
fix Upgrade Godot to 3.3 or later, or avoid autoload exports
gotcha TS2GD is in early beta (v0.0.36); breaking changes may occur without major version bump ↓
fix Lock version in package.json, test compilations after updates
Install
npm install ts2gd yarn add ts2gd pnpm add ts2gd Imports
- init project wrong
npm init ts2gdcorrectts2gd --init - compilation (watch mode) wrong
ts2gd --watchcorrectts2gd - compilation (single build) wrong
ts2gd --buildcorrectts2gd --buildOnly
Quickstart
// Install globally
npm install --global ts2gd
# Initialize a new project
cd my-godot-project
ts2gd --init
# Write a TypeScript script (e.g., src/MyScript.ts)
import { Node2D, Input, KeyList } from "godot"
export default class MyScript extends Node2D {
_ready(): void {
if (Input.is_key_pressed(KeyList.KEY_SPACE)) {
print("Space pressed!")
}
}
}
# Compile
# Watch mode:
ts2gd
# One-time build:
ts2gd --buildOnly