Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When constructing St.Widget, specifying layout_manager should be reflected in types #18

Closed
KSXGitHub opened this issue Feb 11, 2024 · 3 comments

Comments

@KSXGitHub
Copy link

KSXGitHub commented Feb 11, 2024

When one constructs a St.Widget like this:

const myWidget = new St.Widget({
  layout_manager: new Clutter.GridLayout(),
})

The type of myWidget.layout_manager is still LayoutManager, which would make TypeScript errors when one tries to use methods from GridLayout.

Suggestion 1: Multiple type parameters

// St
class Widget<LayoutManagerT extends Clutter.LayoutManager | null = null, LabelActorT extends Clutter.LabelActor | null = null> extends Clutter.Actor<LayoutManagerT, LabelActorT> {
  constructor(config?: Widget.ConstructorProperties<LayoutManagerT, LabelActorT>)
}

// Clutter
interface Actor<LayoutManagerT extends LayoutManager | null, LabelActorT extends LabelActor | null> {
  layout_manager: LayoutManagerT
  layoutManager: LayoutManagerT
  label_actor: LabelActorT
  labelActor: LabelActorT
}

WARNING: ConstructorProperties now shouldn't be a single interface, but a union of snake_case properties and camelCase properties. Keeping it as a single interface would have required user to specify both layout_manager and layoutManager, which would be absurd.

Suggestion 2: Type dictionary as a single type parameter

// St
class Widget<Config extends Widget.ConstructorProperties | null> extends ClutterActor<Config> {
  constructor(config: Config)
}

// Clutter
interface Actor<Config extends Widget.ConstructorProperties | null> {
  layout_manager: Config extends Widget.ConstructorProperties ? Config['layout_manager'] : null
  layoutManager: Config extends Widget.ConstructorProperties ? Config['layoutManager'] : null
  label_actor: Config extends Widget.ConstructorProperties ? Config['label_actor'] : null
  labelActor: Config extends Widget.ConstructorProperties ? Config['labelActor'] : null
}

NOTE: I strongly recommend this solution. ConstructorProperties does not need to change at all.

@KSXGitHub
Copy link
Author

KSXGitHub commented Feb 11, 2024

The two suggestions above still have a flaw: It now requires TypeScript user to pass null explicitly, optional parameter is no longer allowed.

If you want to fix this flaw, then I suggest stop using the class keyword. Instead, you should utilize the TypeScript feature that allows merging variable and type, like so (assuming you choose "suggestion 2"):

const Widget: unknown
  & (new <Config extends Widget.ConstructorProperties> (config: Config) => Widget<Config>)
  & (new (config?: null) => Widget<null>)
interface Widget<Config extends Widget.ConstructorProperties | null> extends Widget.Actor<Config> {}

As for me personally, whether I have to pass null explicitly makes little difference.

@schnz
Copy link
Member

schnz commented Feb 11, 2024

Hey @KSXGitHub,

this repository is dedicated to the gnome-shell types that are usually imported through a resource:///org/gnome/... path. These types are hand-crafted because the upstream repository is using JavaScript (with a few JSDoc annotations from time to time) but there is no official type support.

The types related to gi://... imports, such as St or Clutter and others, are auto-generated via ts-for-gir. I am not that familiar with that repository and don't know whether generics are within the scope of whats possible via the introspection from which the TS types are generated. But this is where this issue ultimately belongs to.

I personally tend to define custom generic types when required. In my experience they are usually only needed in very few places.

@KSXGitHub
Copy link
Author

KSXGitHub commented Feb 11, 2024

@schnz I have created https://github.com/gjsify/types/issues/5 gjsify/ts-for-gir#145

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants