GObject decorators 
Decorators that wrap GObject.registerClass.
Required TypeScript settings
Make sure experimentalDecorators is set to false and target is less than or equal to ES2020 in tsconfig.json.
{
  "compilerOptions": {
    "experimentalDecorators": false,
    "target": "ES2020"
  }
}Example Usage 
import GObject, { register, property, signal } from "gnim/gobject"
@register({ GTypeName: "MyObj" })
class MyObj extends GObject.Object {
  @property(String) myProp = ""
  @signal(String, GObject.TYPE_UINT)
  mySignal(a: string, b: number) {
    // default handler
  }
}What it (roughly) transpiles to
const priv = Symbol("private props")
class MyObj extends GObject.Object {
  [priv] = { "my-prop": "" }
  constructors() {
    super()
    Object.defineProperty(this, "myProp", {
      enumerable: true,
      configurable: false,
      set(value) {
        if (this[priv]["my-prop"] !== value) {
          this[priv]["my-prop"] = v
          this.notify("my-prop")
        }
      },
      get() {
        return this[priv]["my-prop"]
      },
    })
  }
  mySignal(a, b) {
    return this.emit("my-signal", a, b)
  }
  on_my_signal(a, b) {
    // default handler
  }
}
GObject.registerClass(
  {
    GTypeName: "MyObj",
    Properties: {
      "my-prop": GObject.ParamSpec.string(
        "my-prop",
        "",
        "",
        GObject.ParamFlags.READWRITE,
        "",
      ),
    },
    Signals: {
      "my-signal": {
        param_types: [String.$gtype, GObject.TYPE_UINT],
      },
    },
  },
  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 are split into three decorators:
type PropertyTypeDeclaration<T> =
  | ((name: string, flags: ParamFlags) => ParamSpec<T>)
  | { $gtype: GType<T> }
function property<T>(typeDeclaration: PropertyTypeDeclaration<T>): void
function setter<T>(typeDeclaration: PropertyTypeDeclaration<T>): void
function getter<T>(typeDeclaration: PropertyTypeDeclaration<T>): voidThese decorators take a single parameter that defines the type:
- any class that has a registered - GType. This includes the globally available- String,- Number,- Booleanand- ObjectJavaScript constructors, which are mapped to their relative- GObject.ParamSpec.- Object:- ParamSpec.jsobject
- String:- ParamSpec.string
- Number:- ParamSpec.double
- Boolean:- ParamSpec.boolean
- GObject.Objectand its subclasses
 
- a function that produces a - ParamSpecwhere the passed name is a kebab-cased name of the property (for example- myProp->- my-prop), and flags is one of:- ParamFlags.READABLE,- ParamFlags.WRITABLE,- ParamFlags.READWRITE.ts- const Percent = (name: string, flags: ParamFlags) => GObject.ParamSpec.double(name, "", "", flags, 0, 1, 0) @register() class MyObj extends GObject.Object { @property(Percent) percent = 0 }
property 
The property decorator lets you declare a read-write property.
@register()
class MyObj extends GObject.Object {
  @property(String) myProp = ""
}This will create a getter and setter for the property and will also emit the notify signal when the value is set to a new value.
WARNING
The value is checked by reference, which is important if your property is an object type.
const dict = obj.prop
dict["key"] = 0
obj.prop = dict // This will not emit notify::prop
obj.prop = { ...dict } // This will emit notify::propWhen using custom subclasses as properties, you might want to annotate its $gtype.
@register()
class DeepProp extends GObject.Object {
  declare static $gtype: GObject.GType<DeepProp>
}
@register()
class MyClass extends GObject.Object {
  @property(DeepProp) prop: DeepProp
}getter 
The getter decorator lets you declare a read-only property.
@register()
class MyObj extends GObject.Object {
  @getter(String)
  get readOnly() {
    return "readonly value"
  }
}setter 
The setter decorator lets you declare a write-only property.
@register()
class MyObj extends GObject.Object {
  #prop = ""
  @setter(String)
  set myProp(value: string) {
    if (value !== this.#prop) {
      this.#prop = value
      this.notify("my-prop")
    }
  }
}NOTE
When using setter you will have to explicitly emit the notify signal.
TIP
You can use the setter and getter decorators in combination to declare a read-write property.
Signal decorator 
function signal(
  params: Array<GType>,
  returnType?: GType,
  options?: {
    default?: default
    flags?: SignalFlags
    accumulator?: AccumulatorType
  },
)
function signal(...params: Array<GType>)You can apply the signal decorator to a method where the method is the default handler of the signal.
@register()
class MyObj extends GObject.Object {
  @signal([String, Number], Boolean, {
    default: true,
    accumulator: GObject.AccumulatorType.FIRST_WINS,
  })
  myFirstHandledSignal(str: string, n: number): boolean {
    return false
  }
TIP
It is required to provide a function implementation which becomes the default signal handler. In case you don't want to implement a default handler you can set the default option to false.
class {
  @signal([], Boolean, {
    default: false,
  })
  withoutDefaultImpl(): boolean {
    throw "this never runs"
  }
}You can emit the signal by calling the signal method or using emit.
const obj = new MyObj()
obj.connect("my-signal", (obj, a: string, b: string) => {})
obj.mySig("a", "b")
obj.emit("my-signal", "a", "b")TIP
To make the connect method aware of signals, you can override it.
interface MyObjSignals extends GObject.Object.SignalSignatures {
  "my-signal": MyObj["mySignal"]
}
@register()
class MyObj extends GObject.Object {
  declare $signals: MyObjSignals // this makes signals inferable in JSX
  override connect<S extends keyof MyObjSignals>(
    signal: S,
    callback: GObject.SignalCallback<this, MyObjSignals[S]>,
  ): number {
    return super.connect(signal, callback)
  }
}Register decorator 
Every GObject.Object subclass has to be registered. You can 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 if you define any.