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.

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
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
npm install ts2gd
yarn add ts2gd
pnpm add ts2gd

Installs ts2gd globally, initializes a Godot project, writes a basic TypeScript script, and compiles it to GDScript.

// 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