TypeScript binding generator for GJS and node-gtk (in a very early stage). Inspired by gir2dts but re-written and re-designed to be a more thorough TypeScript description of the GObject introspection interfaces.
The definitions can be used for both TypeScript or JavaScript projects.
git clone https://github.com/sammydre/ts-for-gjs
cd ts-for-gjs
npm install
npm link
After you have linked this project you can use the ts-for-gir
command in you project:
$ ts-for-gir --help
Typescript .d.ts generator from GIR for gjs or node-gtk
VERSION
ts-for-gir/1.0.0 linux-x64 node-v12.14.1
USAGE
$ ts-for-gir [COMMAND]
COMMANDS
generate Generates .d.ts files from GIR for gjs or node-gtk
help display help for ts-for-gir
list Lists all available GIR modules
$ ts-for-gir generate --help :(
Generates .d.ts files from GIR for gjs or node-gtk
USAGE
$ ts-for-gir generate MODULES
ARGUMENTS
MODULES [default: *] GIR modules to load, e.g. 'Gio-2.0'. Accepts multiple modules
OPTIONS
-b, --buildType=lib|types [default for gjs: lib, default for node: types] Force the definitions generation type
-e, --environments=gjs|node [default: gjs,node] javascript environment
-g, --girDirectories=girDirectories [default: /usr/share/gir-1.0] GIR directory
-h, --help show CLI help
-i, --ignore=ignore [default: ] modules that should be ignored
-o, --outdir=outdir [default: @types] directory to output to
-p, --print print the output to console and create no files
-v, --verbose Switch on/off the verbose mode
--configName=configName name of the config if you want to use a different name
--ignoreConflicts Do not ask for package versions if multiple versions are found
--pretty prettifies the generated .d.ts files
--exportDefault Use export default for compatibility with gjs's ES module mode
EXAMPLES
# Run 'ts-for-gir generate' in your gjs or node-gtk project to generate typings for your project, pass the gir modules you need for your project
ts-for-gir generate
# You can also use wild cards
ts-for-gir generate Gtk*
# If you want to parse all of your locally installed gir modules run
ts-for-gir generate '*'
# Generate .d.ts. files only for gjs
ts-for-gir generate '*' -e gjs
# Generate .d.ts. files only for node
ts-for-gir generate '*' -e node
# Use a special config file
ts-for-gir generate --configName='.ts-for-gir.gtk4.rc.js'
# Generate .d.ts. files but not for Gtk-3.0 and xrandr-1.3
ts-for-gir generate --ignore=Gtk-3.0 xrandr-1.3
$ ts-for-gir list --help
Lists all available GIR modules
USAGE
$ ts-for-gir list MODULES
ARGUMENTS
MODULES [default: *] GIR modules to load, e.g. 'Gio-2.0'. Accepts multiple modules
OPTIONS
-g, --girDirectories=girDirectories [default: /usr/share/gir-1.0] GIR directory
-h, --help show CLI help
-i, --ignore=ignore [default: true] modules that should be ignored
-v, --verbose Switch on/off the verbose mode
--configName=configName name of the config if you want to use a different name
EXAMPLES
# Lists all available GIR modules in ./vala-girs/gir-1.0
ts-for-gir list -g ./vala-girs/gir-1.0
# Lists all available GIR modules in /usr/share/gir-1.0 but not Gtk-3.0 and xrandr-1.3
ts-for-gir list --ignore=Gtk-3.0 xrandr-1.3
In addition to the option of passing options as a CLI flag, you can also write them in a config file.
To do that, create a new config file called .ts-for-girrc.js
in your project root directory, like this:
module.exports = {
pretty: false,
print: false,
verbose: true,
environments: ['gjs', 'node'],
outdir: '@types',
girDirectories: '/usr/share/gir-1.0',
modules: ['*'],
ignore: [],
exportDefault: true,
inheritance: true,
}
gjs now supports ES modules, which can be activated with its -m flag. Using this in conjunction with "module": "es6"
in tsconfig.json is generally more
convenient than using the imports
global object, because you no longer have to provide an implementation of require
. However, it creates two new
problems for Typescript/ts-for-gjs. The first is that gi
imports use a URI format, which Typescript doesn't support yet. To work around this problem
you can import from a relative filename as usual, and the Javascript stubs generated by ts-for-gjs now forward the imports from the gi
URI.
The second problem is that in ES module mode, gi
imports behave as if they were exported by export default
, which is not backwards compatible with
ts-for-gjs. Where you would previously write:
import * as Gtk from "<path to gi bindings>/Gtk-4.0js"
you now have to write:
import Gtk from "<path to gi bindings>/Gtk-4.0js"
Destructuring individual items in the import statement is not supported for this type of import.
This fork includes an inheritance
option. ts-for-gjs' normal mode is to provide class definitions with copies of all methods etc inherited through
the GObject system, because conventional TS class inheritance can't deal with method name clashes/overloads that can occur in GObject bindings. The
inheritance
option enables a different type of output, taking advantage of an obscure feature of Typescript. Classes are split into an interface and
a constructor with static methods, both having the same name. The constructor can simply not inherit anything, solving the problem for static methods
and pseudo-constructors. As we are generating type mappings, not actual code, these constructors can be used as if they are classes without having to
worry about the missing super
in our representation. The return type of a constructor is an interface, and this does provide the inheritance
information.
All this results in classes that are easier to use because they do not need explicit casting, and smaller definition files.
Unfortunately there are some non-static methods in existing GObject-based code that hide different methods with the same name in parent classes. The
only way this can be handled in Typescript while still using inheritance is to add bogus overloads, but trying to call those overloads will cause
breakage. For example, Gtk.ToolShell
's get_style
method clashes with Gtk.Widget
's get_style
. Therefore you should use them like this:
Gtk.ToolShell.prototype.get_style.call(widget); Gtk.Widget.prototype.get_style.call(widget);
Run npm run regress
or ts-for-gir --configName='.ts-for-gir.regress.rc.js'
in the root of this project to generate the type definitons for the examples
Now open some code with an editor that understands TypeScript and see what happens, for example Visual Studio Code.
code examples/gjs/browser
Install GObject Introspection Repository files:
# Ubuntu 18.04
sudo apt update && sudo apt install \
libappindicator3-dev \
libgda-5.0-dev \
libgirepository1.0-dev \
libgtk-3-dev \
libgtksourceview-3.0-dev \
libnotify-dev \
libsoup2.4-dev \
libwebkit2gtk-4.0-dev
Generate example type definitions:
npm run regress
Run npm link
, this is similar to npm -g install ts-for-gir
but links to your local development repository which allows you to test your changes directly.
Now you can execute ts-for-gir
anywhere on your system:
ts-for-gir --help
To run our ava tests just run:
npm run test:ava
We have a test wich tries to generate the type definition files for all gir files from the vala-girs repository.
Before you can run this test you need to checkout the vala-girs submodule, to do that run this in the root of ts-for-gjs:
git submodule update --init
Now you can run the test with
npm run test:girs
- gnome-gtk - Typescript bindings for gnome gtk
- ts-gir - Typescript bindings for GJS
- node-gir-typedef - TypeScript bindings for node-gir
- gir2dts - The project this is inspired by
- gir-dts-generator - The project that inspired this project
- gjs-ts - Typescript bindings for GJS