Better documentation on action/view definitions and their impact on IDE introspection, navigation and refactoring

Author: beepsoftCreated Feb 26, 2024Updated Aug 18, 2025
Labelsdocs or examples

(Creating this issue as a follow-up of this conversion in the mst-gql repo: https://github.com/mobxjs/mst-gql/discussions/445#discussioncomment-8589329)

Another issue that may worth mentioning or explaining more in the docs.

If you declare the actions like this (version 1):

typescript
const M = types
  .model('MyModel', {})
  .actions(self => ({
      action1(){},
      action2(){}
  }))

... you won't get proper IDE introspection, navigation and refactoring support. For example, if you Cmd+Click on action1() to see where it is referenced, IntelliJ jumps here:

node_modules/mobx-state-tree/dist/types/complex-types/model.d.ts

bash
export interface ModelActions {
    [key: string]: FunctionWithFlag;
}

You can also use this (version 2):

typescript
const M = types
  .model('MyModel', {})
  .actions(self => {
    function action1(){}
    function action2(){}
    
    return {
      action1,
      action2
    }
  })

This is the worst: Cmd+Click jumps in to the return{} and if you Cmd+Click inside return{} it jumps to the function definition no the usages.

And finally, you can assign the actions to a named variable, which you return (version 3):

typescript
const M = types
  .model('MyModel', {})
  .actions(self => {
      const actions = {
          action1(){},
          action2(){}
      }
      return actions
  })

In this case Cmd+Click on actions1() will correctly list or jump to its usages and can refactor.

This is a huge difference in DX!.

Version 1 and 2 are the default suggestions in the docs now: https://mobx-state-tree.js.org/concepts/actions

Version 3 is mentioned as a tip: https://mobx-state-tree.js.org/tips/typescript, however, it comes with a note in bold:

NOTE: the last approach will incur runtime performance penalty as accessing such computed values (e.g. inside render() method of an observed component) always leads to full recompute (see this issue for details). For a heavily used computed properties it's recommended to use one of above approaches.

I guess this only refers to views, but should be OK for actions and volatile.