GObject decorators
Decorators that wrap GObject.registerClass.
Read more about GObjects in GJS on gjs.guide.
Required TypeScript settings
Make sure experimentalDecorators is set to true.
{ "compilerOptions": { "experimentalDecorators": true } }Example Usage
import GObject from "gi://GObject?version=2.0"
import { register, property, signal } from "gnim/gobject"
@register
class MyObj extends GObject.Object {
@property myProp: string = ""
@signal
mySignal(a: string, b: number): void {
// default handler
}
}What it (roughly) transpiles to
const priv = Symbol("private props")
class MyObj extends GObject.Object {
[priv] = { "my-prop": "" }
get myProp() {
return this[priv]["my-prop"]
}
set myProp() {
if (this[priv]["my-prop"] !== value) {
this[priv]["my-prop"] = v
this.notify("my-prop")
}
}
mySignal(a, b) {
return this.emit("my-signal", a, b)
}
on_my_signal(a, b) {
// default handler
}
}
GObject.registerClass(
{
Properties: {
"my-prop": GObject.ParamSpec.string(
"my-prop",
"",
"",
GObject.ParamFlags.READWRITE,
"",
),
},
Signals: {
"my-signal": {
param_types: [String.$gtype, Number.$gtype],
return_type: GObject.VoidType.$gtype,
},
},
},
MyObj,
)NOTE
Property accessors are defined on the object instance and not the prototype. This might change in the future. Stage 3 decorators are adding a new keyword accessor for declaring properties, which marks properties to expand as get and set methods on the prototype. The accessor keyword is currently not supported by these decorators.
Property decorator
Property declarations can be used on fields and accessors:
class MyObject {
@property
field: number = 1
@property
get readonly(): number {}
@property
set writeonly(v: number) {}
@property
get readwrite(): number {}
set readwrite(v: number) {}
}Property type declaration
The runtime type of the property will be inferred from TypeScript annotations. Optionally, it can be explicitly declared by passing an argument to the decorator.
type PropertyTypeDeclaration<T = unknown> =
| ((name: string, flags: ParamFlags) => ParamSpec<T>)
| ParamSpec<T>
| GType<T>
| { $gtype: GType<T> }The declaration can be
any class that has a registered
GType. This includes the globally availableString,Number,BooleanandObjectJavaScript constructors and any class that inherits fromGObject.Object.a function that produces a
ParamSpecwhere the passed name is a kebab cased version of the name of the property (for examplemyProp->my-prop), and flags is one of:ParamFlags.READABLE,ParamFlags.WRITABLE,ParamFlags.READWRITE.
class MyObject {
@property(GObject.UInt)
guint = 0
@property((name, flags) =>
GObject.ParamSpec.enum(
name,
null,
null,
flags,
Gtk.Orientation,
Gtk.Orientation.VERTICAL,
),
)
myOrientation = Gtk.Orientation.VERTICAL
}Property accessors
When implementing property setters you will also need to explicitly emit notify signals.
class MyObject {
#prop: number = 1
@property
set myProp(v: number) {
if (this.#prop !== v) {
this.#prop = v
this.notify("my-prop")
}
}
}Signal decorator
Signal decorator can be used on methods which will emit the signal:
class {
@signal
mySignal(arg: number): void {
// default handler
}
}Signal type declaration
The runtime type of the parameters and return type will be inferred from TypeScript annotations. Optionally they can be explicitly declared.
class MyObject {
@signal([GObject.UInt], GObject.VoidType)
mySignal(arg: number): void {
// default handler
}
}SignalOptions
type SignalOptions = {
default?: boolean
flags?: SignalFlags
accumulator?: AccumulatorType
}Passing default: false to the signal will skip registering the method as a default handler
class MyObject {
@signal({ default: false })
s() {
throw "this is never called"
}
@signal([], GObject.VoidType, {
default: false,
})
s() {
throw "this is never called"
}
}Register decorator
@register
class MyObj extends GObject.Object {}You can optionally pass the same options to this decorator as you would to GObject.registerClass.
@register({ GTypeName: "MyObj" })
class MyObj extends GObject.Object {}TIP
This decorator registers properties and signals defined with decorators, so make sure to use this and not GObject.registerClass.