GirGen
GIR Parser and type generator.
Install
There are pre built binaries for linux-x64 and linux-arm64 published on NPM.
Otherwise you can install from crates.io using cargo.
TypeScript
Generate a standalone package that contains every namespace found in the given directories.
[!TIP]
You can use the Gnome flatpak SDK to acquire GIR files on systems that don't have them in one place, e.g NixOS or when you are targeting Flatpak.
By default it will generate the package to .types/gi which you can then source
in tsconfig.json.
[!TIP]
Don't forget to gitignore generated files.
Note that when using --alias flag to generate non version imports such as
gi://Gtk make sure to ignore the version you don't need so that it does not
end up as a union of the two versions.
TypeScript Annotations
GObject has a few additional concepts about class methods and properties that cannot be expressed with TypeScript alone. For these girgen generates type only fields on classes and interfaces.
We have annotations for:
- signals
- readable properties
- writable properties
- construct-only properties
When implementing a GObject subclass you might want to annotate a subset of these or all of these depending on usecase.
Every class that inherits from GObject is going to include a namespace
containing type declarations where each member is written in kebab-case:
namespace MyClass {
export interface SignalSignatures extends GObject.Object.SignalSignatures {
// simple signal
"my-signal"(arg: number): void
// detailed signals are annotated with the `::{}` suffix
"my-detailed-signal::{}"(arg: number): void
}
// ReadableProperties is also used for notify signal annotations
export interface ReadableProperties
extends GObject.Object.ReadableProperties {
// property which has a public getter
"my-prop": number
}
export interface WritableProperties
extends GObject.Object.WritableProperties {
// property which has a public setter
"my-prop": number
}
export interface ConstructOnlyProperties
extends GObject.Object.ConstructOnlyProperties {
// property which can only be set at construction
"my-ctor-prop": number
}
}
And the Class will refer to these using special $ prefixed fields:
[!IMPORTANT]
These fields don't exist at runtime, they are used by other APIs to introspect GObjects.
class MyClass extends GObject.Object {
declare readonly $signals: MyClass.SignalSignatures
declare readonly $readableProperties: MyClass.ReadableProperties
declare readonly $writableProperties: MyClass.WritableProperties
declare readonly $constructOnlyProperties: MyClass.ConstructOnlyProperties
static {
GObject.registerClass(
{
Signals: {
"my-signal": {
param_types: [GObject.TYPE_DOUBLE],
},
"my-detailed-signal": {
param_types: [GObject.TYPE_DOUBLE],
flags: GObject.SignalFlags.DETAILED,
},
},
Properties: {
"my-prop": GObject.ParamSpec.double(
"my-prop",
null,
null,
GObject.ParamFlags.READWRITE,
-GObject.Double.MAX_VALUE,
GObject.Double.MAX_VALUE,
),
"my-ctor-prop": GObject.ParamSpec.double(
"my-ctor-prop",
null,
null,
GObject.ParamFlags.CONSTRUCT_ONLY,
-GObject.Double.MAX_VALUE,
GObject.Double.MAX_VALUE,
),
},
},
MyClass,
)
}
// GObject.ConstructorProps can be used to infer props from the annotations
constructor(props: Partial<GObject.ConstructorProps<MyClass>>) {
super(props)
// note that properties will be annotated as camelCase
console.log(props.myProp, props.myCtorProp)
}
}
Methods such as connect(), emit(), notify() will infer from these
annotations.
const instance = new MyClass()
instance.connect("my-signal", (source, arg) => {
console.log(arg)
})
instance.connect("my-detailed-signal::detail", (source, arg) => {
console.log(arg)
})
instance.connect("notify::my-prop", (_, pspec) => {
console.log(pspec.name)
})
Due to how TypeScript this type works, you need to annotate this or use a
typecast to correctly infer types within the class.
class MyClass {
myFn(this: MyClass) {
this.emit("my-signal", 0)
}
myFn() {
const self = this as MyClass
self.emit("my-signal", 0)
}
}