Skip to content

Instantly share code, notes, and snippets.

@leevigraham
Last active October 19, 2021 10:42
Show Gist options
  • Save leevigraham/ef462b50ae196b506cbdfea56ca6277f to your computer and use it in GitHub Desktop.
Save leevigraham/ef462b50ae196b506cbdfea56ca6277f to your computer and use it in GitHub Desktop.
Stimulus + Typescript Types

In stimulusjs you can define a component (known as a controller) like so:

import { Controller } from "stimulus";

export default class extends Controller {
  static targets = ["item"];
  
  function connect() {
    if(this.hasItemTarget) {
      console.log(this.itemTarget)
    }
  }
}

Under the hood stimulus creates the following class properties dynamically:

  • this.hasItemTarget
  • this.itemTarget

These class properties are created at runtime.

To get around this in typescript we need to define them manually:

import { Controller } from "stimulus";

export default class extends Controller {

  static targets = ["item"];

  // use declare to strip type definitions during transformation
  declare hasItemTarget: boolean
  declare itemTarget: HTMLElement

  function connect() {
    if(this.hasItemTarget) {
      console.log(this.itemTarget)
    }
  }
}

Obviously this can get repetative as there are more targets defined.

So is there any way with utility types or any other black magic to make these dynamic properties recognised by typescript?

@wesbos
Copy link

wesbos commented Aug 12, 2021

So I think the best way here is to use declaration merging.

You can do this in a single file, or in a global defs.d.ts file.

import { Controller } from "stimulus";

declare module "stimulus" {
  class Controller {
    hasItemTarget: boolean;
    itemTarget: HTMLElement;
  }
}

This will merge with the built in controller types and add those two properties each time you extend the controller

@leevigraham
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment