{"id":13682965,"url":"https://github.com/johnfn/ts2gd","last_synced_at":"2025-03-04T03:36:30.593Z","repository":{"id":37039946,"uuid":"316784592","full_name":"johnfn/ts2gd","owner":"johnfn","description":"💥 Compile TypeScript to GDScript for Godot","archived":false,"fork":false,"pushed_at":"2022-06-18T10:50:53.000Z","size":3540,"stargazers_count":210,"open_issues_count":39,"forks_count":15,"subscribers_count":9,"default_branch":"main","last_synced_at":"2024-11-12T02:35:51.521Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/johnfn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-11-28T17:19:25.000Z","updated_at":"2024-10-15T02:50:02.000Z","dependencies_parsed_at":"2022-06-25T08:07:21.889Z","dependency_job_id":null,"html_url":"https://github.com/johnfn/ts2gd","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnfn%2Fts2gd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnfn%2Fts2gd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnfn%2Fts2gd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnfn%2Fts2gd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johnfn","download_url":"https://codeload.github.com/johnfn/ts2gd/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241780485,"owners_count":20019058,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T13:01:56.448Z","updated_at":"2025-03-04T03:36:30.573Z","avatar_url":"https://github.com/johnfn.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","others","Other Language Targets"],"sub_categories":[],"readme":"# ts2gd: Compile TypeScript to GDScript\n\n⚠️ Need help? Contact me on Discord: johnfn#0001.\n\n## Why use ts2gd?\n\n- Compiles directly to GDScript with virtually no performance penalty - no embedded JS runtime.\n- Insanely fast dev experience - after startup, incremental compiles take under a tenth of a second.\n- Provides crazy good autocomplete and documentation.\n- Use all of TS's extremely powerful type system.\n\n## Install:\n\n`npm install --global ts2gd`\n\nThen just run `ts2gd` in your favorite Godot project folder.\n\n![](readme/output.gif)\n\n## Why?\n\nGDScript is a great language - it's perfectly designed for quick prototyping. But it lacks the type-safety and maturity of a language like TypeScript. By compiling TS into GD, we can get the best of both worlds: a rapid prototyping language that compiles virtually instantaneously, that also comes with excellent typesafety.\n\nWe can also get really, really good autocomplete and refactoring support.\n\n## Usage\n\nTo initialize a new project:\n\n```\nts2gd --init\n```\n\nTo watch TS files for changes and automatically compile them to GDScript:\n\n`ts2gd`\n\nTo compile all source files once:\n\n`ts2gd --buildOnly`\n\n## Details and Differences\n\n### `get_node`\n\n`get_node` has been supercharged - it will now autocomplete the names of all\nchild nodes. And yes, this means that if you arrange your nodes later, you'll\nget type errors if you break any `get_node` calls!!\n\n|        Godot hierarchy         |          ts2gd autocomplete           |\n| :----------------------------: | :-----------------------------------: |\n| ![](readme/get_node_godot.png) | ![](readme/get_node_autocomplete.png) |\n\nts2gd also provides a way to get any node by name, even the ones it can't verify exist:\n\n```\nthis.get_node\u003cLabel\u003e(\"MyLabel\")\n```\n\nN.B. It _should_ be possible to use ts2gd without _ever_ having to revert to the\nsecond get_node call with the type parameter. Please open a GitHub issue if you\nfeel this isn't the case.\n\n### `load` / `preload`\n\n`preload` and `load` work as normal - plus they have good autocomplete support, and they return the proper type of the thing you're loading.\n\n[\u003cimg src=\"readme/preload.png\" width=\"250\"/\u003e](readme/preload.png)\n\n### Enums\n\nGodot decides to put a bunch of enum values into global scope. I think this clutters things up: the global scope has tons of mostly useless enum values in it, and it's impossible to tell what property belongs to which enum. So we move them into `EnumName.PropertyName` instead. This is extra nice because now if you type `EnumName` you get autocomplete of all the types in that Enum.\n\nFor instance,\n\n```\nInput.is_key_pressed(KEY_W)\n```\n\nbecomes\n\n```\nInput.is_key_pressed(KeyList.KEY_SPACE)\n```\n\nFor the full list of namespaced enums, you can see the generated @globals.d.ts file.\n\nIn the future, this could become a configuration setting on tsgd.json.\n\n### `rpc`\n\nThe RPC syntax has been improved.\n\nGDScript:\n\n```\nthis.rpc(\"my_rpc_method\", \"some-argument)\n```\n\nTypeScript:\n\n```\nthis.my_rpc_method.rpc(\"some-argument\")\n```\n\n### `signals`\n\nSignals have been improved. All signals now start with `$` and are properties of the class they're defined on.\n\n#### `connect`\n\nThis is what connect looks like in ts2gd:\n\n```\nthis.my_button.$pressed.connect(() =\u003e {\n  print(\"Clicked the button!)\n})\n```\n\n#### `yield`\n\nThis is what yield looks like in ts2gd:\n\n```\nyield this.get_tree().$idle_frame\n```\n\n#### `emit`\n\nThis is what emit looks like in ts2gd:\n\n```\nclass MySignallingClass extends Node2D {\n  $my_signal!: Signal // ! to avoid the TS error about this signal being unassigned\n\n  _process() {\n    this.$my_signal.emit()\n  }\n}\n```\n\n### Autoloads\n\nIn order to make a class autoload, decorate your class with `@autoload`, and create and export an instance of the class. ts2gd will automatically add it as an AutoLoad in your Godot project (assuming you're on version 3.3!)\n\nHere's a full example of an autoload class.\n\n```\n@autoload\nclass MyAutoloadClass extends Node2D {\n  public hello = \"hi\"\n}\n\nexport const MyAutoload = new MyAutoloadClass()\n```\n\n### `@export`\n\nIn order to mark an instance variable as `export`, use `@exports`, e.g.:\n\n```\nclass ExportExample extends Node2D {\n  @exports\n  public hello = \"exported\"\n}\n```\n\n### `tool`\n\nIn order to mark a script as `tool`, use `@tool`.\n\n```\n@tool\nclass MyToolScript extends Node2D {\n  // ... do some tool script work here\n}\n```\n\n### `@remotesync`, `@remote`\n\nTo mark a method as remotesync or remote, use `@remotesync` and `@remote`, respectively.\n\n### `Vector2` / `Vector3` operator overloading\n\nTypeScript sadly has no support for operator overloading.\n\n```\nconst v1 = Vector(1, 2)\nconst v2 = Vector(1, 2);\n\nv1.add(v2); // v1 + v2\nv1.sub(v2); // v1 - v2\nv1.mul(v2); // v1 * v2\nv1.div(v2); // v1 / v2\n```\n\nThe add/sub/mul/div gets compiled into the corresponding arithmatic.\n\n### Dictionary\n\nThe default TS dictionary (e.g. `const dict = { a: 1 }`) only supports string, number and symbol as keys. If you want anything else, you can just use the Dictionary type, and use `.put` instead of square bracket access.\n\n```\nconst myComplexDict: Dictionary\u003cNode2D, int\u003e = todict({})\n\nmyComplexDict.put(myNode, 5)\n```\n\n### Latest and greatest Godot definitions\n\nIf you'd like ts2gd to generate the latest TS definitions from Godot, clone the Godot repository and point it at the 3.x tag. Then add the following to your ts2gd.json:\n\n```\n  \"godotSourceRepoPath\": \"/path/to/your/godot/clone\"\n```\n\nThis shouldn't be necessary unless you want some really recent features from Godot, or you're developing the ts2gd compiler.\n\n# Common Issues\n\n## Godot Editor Formatting\n\nts2gd generates code with 2 spaces as indent. If Godot keeps changing your .gd files when opening/saving them, change the settings:\n\n- Goto Editor -\u003e Editor Settings -\u003e Text Editor -\u003e Indent\n- And switch to Type: Spaces and Size: 2\n\n## Ignoring sub directories containing TypeScript files\n\nIf you would like to tell ts2gd to ignore certain TypeScript files, you can add `\"ignore\": /* list of files */` to your ts2gd.json file.\n\n- To ignore a file: `\"ignore\": [\"ignore_me.ts\"]`\n- Two files: `\"ignore\": [\"ignore_me.ts\", \"ignore_me_too.ts\"]`\n- Everything inside a directory: `\"ignore\": [\"**/ignore_me/**\"]`\n\nNeed something more customized? You can provide an array of [anymatch](https://www.npmjs.com/package/anymatch) strings or globs.\n\n# Roadmap\n\n## Road to usability\n\n- [x] load(\"myscene.tscn) should return a `PackedScene\u003cT\u003e` where T is the type of the root node of the scene\n- [x] `connect()`\n- [x] When i migrate to only using compiled gdscripts, adjust the imports() appropriately to figure out where the compiled versions are.\n- [x] Compile \"Yield\" to \"yield\"\n- [x] Translate `add()`, `sub()`, etc\n- [x] mark int/float in API\n- [x] add documentation for class names.\n- [x] With int/float, mark down the variables we've determined to be int/float so we can use that information rather than TS telling us that everything is number.\n- [x] Autocomplete relative node paths as well as absolute ones\n- [x] `extends` must be transpiled before everything else, including enum declarations and other top level things\n- [x] Godot expects methods like \\_process to _always_ have a float parameter, but TS does not require this. It should be added implicitly.\n- [ ] explain tne `enum` thing better\n- [ ] @node annotations to say which node a class belongs to\n- [x] handle parameters to \\_functions that aren't provided in TS by autofilling them in Godot\n- [x] `callables`\n- [x] Handle passing anonymous functions around - probably with funcref for now.\n- [ ] Handle the thing where if u never yield its never a coroutine\n- [ ] Either allow the user to point their ts2gd at a godot source download, or more likely, just grab it from online? Idk.\n- [ ] Fallthrough cases in switch are currently not supported.\n- [ ] generate Godot without warnings (as much as possible)\n- [x] `tool`\n- [ ] it would be very nice to be able to pass in anonymous functions in place of callables, and have the compiler sort that out.\n\n## Road to superior development\n\n- [x] Autoload classes should have an @annotation and then get automatically added to the project\n- [x] get_nodes_in_group should parse scene to determine a more accurate return type\n- [x] Mark unused variables with \\_ to avoid warnings\n- [x] parse the bbcode in the XML into markdown that TS can read.\n- [x] when scenes are updated, update their corresponding definition files\n- [ ] create scripts and attach them to nodes directly through the editor - perhaps with @Node(\"/blah\")\n- [x] don't hide object autocomplete names\n- [x] strongly type input action names\n- [x] handle renames better - delete the old compiled file, etc.\n- [ ] refactoring class names doesn't really work right now because i think we need to rename types in tscn files...\n- [ ] would be nice to declare multiple classes in the same .ts file and have the compiler sort it out\n- [x] add a way to install ts2gd as a global command\n- [x] ensure that signal arguments match up\n- [ ] add a way to use ts2gd via installer rather than command line\n- [ ] Whether to hide away constants into enums or not could be parameterizeable. It is _correct_ to hide them into enums, but it will be confusing for people who haven't read the README, which is probably everyone.\n- [ ] Some sort of error if an autoload class is not entirely static.\n- [x] yield(this.get_tree(), \"idle_frame\"); could autocomplete idle_frame? it's possible: just get all the signals on the object.\n- [ ] Fancy TS/JS features\n  - [x] destructuring\n  - [ ] ... spread operator\n- [x] Map, filter, etc? even though they aren't part of godot, it would be nice to have them.\n- [x] ../ node paths (note: impossible)\n- [x] Break our assumption that filename === classname\n- [ ] Onready vs nonready - maybe we don't have to mark everything as an onready var? Is there an advantage to so doing?\n- [x] ts2gd: Handle adding new files.\n- [x] ts2gd: Handle deleting old files.\n- [x] ts2gd: Random newlines at beginning of file.\n- [x] Is there a better way to do Dictionary, with strongly typed k/v?\n- [ ] Sourcemaps / debugging???\n- [ ] use LSP to handle operator overloading, sourcemap issues...?!?\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnfn%2Fts2gd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohnfn%2Fts2gd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnfn%2Fts2gd/lists"}