Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mobx State Tree reference type and Typescript

I'm using mobx-state-tree with Typescript in a React application. And, I'm having an issue with Typescript where it complains about the type of the mobx type types.safeReference. It looks like the type of safeReference in the model definition is different from its type when you use .create() to actually create an instance of the model. In my code, selectedProduct's type is converted to string | number | undefined | null in productStore, but in the model definition is IStateTreeNode<...> | undefined | null and that's why I get an error in my root store. How can I fix that?

Here's my Product store:

import { types } from "mobx-state-tree";

const Product = types.model("Product", {
   id: types.identifier,
   name: types.string
})

const ProductStore = types
  .model("ProductStore", {
    products: types.array(Product),
    selectedProduct: types.safeReference(Product),
  })
  .actions((self) => ({
      // actions here
  }));

export const productStore = ProductStore.create({
  products: [],
  selectedProduct: undefined // the type here is different from the type in the actual model
});

And, here's my root store:

import { types } from "mobx-state-tree";
import ProductStore, { productStore } from "./product-store";

const RootStore = types.model('RootStore', {    
  productStore: ProductStore 
})

export const rootStore = RootStore.create({
    productStore: productStore // Here is where I get the typescript error.
});

UPDATE:

Another way of reproducing this issue is by trying to create a custom reference. The getter will complain about undefined not being assignable to type {...}.

const ProductByIdReference = types.maybeNull(
  types.reference(Product, {
      get(id: number, parent: Instance<typeof ProductStore>) {
          return parent.products.find(p => p.id === id) || undefined
      },
      set(value: Instance<typeof Product>) {
          return value.id
      }
  })
)
like image 638
ataravati Avatar asked Jan 29 '21 16:01

ataravati


1 Answers

Generally speaking when you are trying to use a snapshot where an instance is typically used, you use cast. When you are trying to use an instance where a snapshot is typically used, you use castToSnapshot.

export const rootStore = RootStore.create({
    productStore: castToSnapshot(productStore)
});
like image 115
Tholle Avatar answered Oct 01 '22 20:10

Tholle