Тип ссылки Mobx State Tree и Typescript

Я использую дерево состояний mobx с Typescript в приложении React. И у меня проблема с Typescript, когда он жалуется на тип типа mobx types.safeReference. Похоже, что тип safeReference в определении модели отличается от его типа, когда вы используете .create() для фактического создания экземпляра модели. В моем коде тип selectedProduct преобразуется в string | number | undefined | null в productStore, но в определении модели IStateTreeNode<...> | undefined | null, и поэтому я получаю ошибку в моем корневом хранилище. Как я могу это исправить?

Вот мой продуктовый магазин:

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
});

И вот мой корневой магазин:

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.
});

ОБНОВЛЕНИЕ:

Другой способ воспроизвести эту проблему - попытаться создать настраиваемую ссылку. Получатель будет жаловаться на то, что undefined не может быть назначен типу {...}.

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
      }
  })
)

person ataravati    schedule 29.01.2021    source источник
comment
Я не уверен, что это недосмотр или предполагаемое поведение, очень интересно. Вместо того, чтобы экспортировать ProductStore синглтон, не могли бы вы позволить RootStore создать его за вас? Т.е. export const rootStore = RootStore.create({ productStore: { products: [], selectedProduct: undefined } });   -  person Tholle    schedule 29.01.2021
comment
Нет, это должен быть синглтон.   -  person ataravati    schedule 29.01.2021
comment
Это тот случай, когда все работает нормально и это просто ошибка TS? Похоже, что RootStore.create ищет необработанное значение, а не созданное хранилище. Если вы передадите ему начальное состояние productStore, а не само хранилище, тогда он будет работать нормально. Не уверен, что это вообще полезно, но этот ответ показывает совсем другой способ объединения магазинов: stackoverflow.com/a/54081439/10431574 < / а>   -  person Linda Paiste    schedule 03.02.2021
comment
В игре есть множество типов утилит github.com/mobxjs/mobx-state-tree/blob/ Но самое нижнее сообщение в цепочке ошибок - это IMSTArray norefer.com / mobxjs / mobx-state-tree / blob / и ожидает фактический массив. Он жалуется, что IMSTArray не имеет всех методов, которые должен иметь массив.   -  person Linda Paiste    schedule 03.02.2021
comment
Спасибо @LindaPaiste и извиняюсь за задержку! Я попробую.   -  person ataravati    schedule 05.02.2021


Ответы (2)


Вообще говоря, когда вы пытаетесь использовать снимок, в котором обычно используется экземпляр, вы используете cast. Когда вы пытаетесь использовать экземпляр, в котором обычно используется снимок, вы используете castToSnapshot < / а>.

export const rootStore = RootStore.create({
    productStore: castToSnapshot(productStore)
});
person Tholle    schedule 23.02.2021
comment
Спасибо! Это работает, и это легко. - person ataravati; 23.02.2021

Я подробно проверил вашу проблему и написал решение, вот как правильно использовать mst rootStore концепцию, нет необходимости создавать экземпляры вашего магазина или объекта, просто @inject это напрямую внутри компонента:

// Product Store
import { types, Instance } from "mobx-state-tree";

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

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

type ProductStoreType = typeof Store;
interface ProductStoreTypeInterface extends ProductStoreType {}
export interface ProductStoreInterface extends Instance<ProductStoreTypeInterface> {}
export const ProductStore: ProductStoreTypeInterface = Store;

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

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

// And now you can create rootStore with empty object
export const rootStore = RootStore.create({});

// Component
import { inject, observer } from 'mobx-react';
import { SettingStoreInterface } from "../settings/SettingStore";
import React from "react";

interface ComponentProps {}

interface InjectedProps extends ComponentProps {
  productStore: ProductStoreInterface;
}

@inject('productStore')
@observer
class SomeComponent extends React.Component<ComponentProps> {
  componentDidMount() {
    const { productStore } = this.props as InjectedProps;
    
    console.log(productStore.products);
  }
}
person kaxi1993    schedule 06.02.2021
comment
Но вы не создаете Магазин продуктов. - person ataravati; 09.02.2021
comment
Он будет создан, когда вы введете его в свой компонент - person kaxi1993; 09.02.2021
comment
Как? Нет кода для его создания. - person ataravati; 09.02.2021
comment
Проверить обновленный ответ - person kaxi1993; 09.02.2021
comment
Это не сработает. Магазин продуктов не создан, поэтому его нельзя ввести. - person ataravati; 09.02.2021
comment
Я весь продукт так построил, вам нужно хотя бы протестировать, прежде чем писать, что он не работает - person kaxi1993; 09.02.2021
comment
Я попробую, но, тем не менее, это решение как есть для меня не сработает, поскольку я использую перехватчики реакции. Мне нужно иметь возможность пользоваться магазинами, используя useContext. - person ataravati; 09.02.2021
comment
Могу переделать для работы с функциональными компонентами - person kaxi1993; 09.02.2021
comment
Дай мне попробовать. Я вернусь к вам. Спасибо! Однако это может занять пару дней. - person ataravati; 09.02.2021