mobx-state-tree icon indicating copy to clipboard operation
mobx-state-tree copied to clipboard

types.reference is not working on instance creation

Open casamia918 opened this issue 3 years ago • 6 comments

Bug report

  • [o ] I've checked documentation and searched for existing issues
  • [o] I've made sure my project is based on the latest MST version
  • [o] Fork this code sandbox or another minimal reproduction.

Sandbox link or minimal reproduction code https://codesandbox.io/s/mobx-state-tree-todolist-forked-cgpms?file=/test..ts

Describe the expected behavior The 'tweet' instance should be used at model creation.

Describe the observed behavior I just copy and paste the document code. But it failed https://github.com/mobxjs/mobx-state-tree/blob/master/README.md#using-a-mst-type-at-design-time

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

// Define a couple models
const Author = types.model({
  id: types.identifier,
  firstName: types.string,
  lastName: types.string,
})

const Tweet = types.model({
  id: types.identifier,
  author: types.reference(Author), // stores just the `id` reference!
  body: types.string,
  timestamp: types.number,
})

// Define a store just like a model
const RootStore = types.model({
  authors: types.array(Author),
  tweets: types.array(Tweet),
})

// Instantiate a couple model instances
const jamon = Author.create({
  id: "jamon",
  firstName: "Jamon",
  lastName: "Holmgren",
})

const tweet = Tweet.create({
  id: "1",
  author: jamon.id, // just the ID needed here
  body: "Hello world!",
  timestamp: Date.now(),
})

// Now instantiate the store!
const rootStore = RootStore.create({
  authors: [jamon],
  tweets: [tweet], // ***** Error below *****
})



const tweet: {
    id: string;
    author: {
        id: string;
        firstName: string;
        lastName: string;
    } & NonEmptyObject & IStateTreeNode<IReferenceType<IModelType<{
        id: ISimpleType<string>;
        firstName: ISimpleType<string>;
        lastName: ISimpleType<...>;
    }, {}, _NotCustomized, _NotCustomized>>>;
    body: string;
    timestamp: number;
} & NonEmptyObject & IStateTreeNode<...>
Type '{ id: string; author: { id: string; firstName: string; lastName: string; } & NonEmptyObject & IStateTreeNode<IReferenceType<IModelType<{ id: ISimpleType<string>; firstName: ISimpleType<string>; lastName: ISimpleType<...>; }, {}, _NotCustomized, _NotCustomized>>>; body: string; timestamp: number; } & NonEmptyObject &...' is not assignable to type 'ModelCreationType<ExtractCFromProps<{ id: ISimpleType<string>; author: IReferenceType<IModelType<{ id: ISimpleType<string>; firstName: ISimpleType<string>; lastName: ISimpleType<string>; }, {}, _NotCustomized, _NotCustomized>>; body: ISimpleType<...>; timestamp: ISimpleType<...>; }>>'.
  Type '{ id: string; author: { id: string; firstName: string; lastName: string; } & NonEmptyObject & IStateTreeNode<IReferenceType<IModelType<{ id: ISimpleType<string>; firstName: ISimpleType<string>; lastName: ISimpleType<...>; }, {}, _NotCustomized, _NotCustomized>>>; body: string; timestamp: number; } & NonEmptyObject &...' is not assignable to type 'Partial<ExtractCFromProps<{ id: ISimpleType<string>; author: IReferenceType<IModelType<{ id: ISimpleType<string>; firstName: ISimpleType<string>; lastName: ISimpleType<string>; }, {}, _NotCustomized, _NotCustomized>>; body: ISimpleType<...>; timestamp: ISimpleType<...>; }>>'.
    Types of property 'author' are incompatible.
      Type '{ id: string; firstName: string; lastName: string; } & NonEmptyObject & IStateTreeNode<IReferenceType<IModelType<{ id: ISimpleType<string>; firstName: ISimpleType<string>; lastName: ISimpleType<...>; }, {}, _NotCustomized, _NotCustomized>>>' is not assignable to type 'ReferenceIdentifier'.
        Type '{ id: string; firstName: string; lastName: string; } & NonEmptyObject & IStateTreeNode<IReferenceType<IModelType<{ id: ISimpleType<string>; firstName: ISimpleType<string>; lastName: ISimpleType<...>; }, {}, _NotCustomized, _NotCustomized>>>' is not assignable to type 'number'.ts(2322)


casamia918 avatar Jul 08 '21 10:07 casamia918

Ok. I found answer by myself. Using castToReferenceSnapshot resolve the error.

But the document needs to be updated.


import { types, castToReferenceSnapshot } from "mobx-state-tree"

...


// Now instantiate the store!
const rootStore = RootStore.create({
  authors: [jamon],
  tweets: [castToReferenceSnapshot(tweet)],
})

casamia918 avatar Jul 08 '21 10:07 casamia918

Just curious, why not just pass the POJOs directly to RootStore.create?

const jamon = {
  id: "jamon",
  firstName: "Jamon",
  lastName: "Holmgren",
};

const tweet = {
  id: "1",
  author: jamon.id,
  body: "Hello world!",
  timestamp: Date.now(),
};

const rootStore = RootStore.create({
  authors: [jamon],
  tweets: [tweet],
});

MarkLeMerise avatar Jul 09 '21 03:07 MarkLeMerise

Hm, yeah, we need to fix this.

Another way to fix this is with makeObservable, but I don't like that very much either. Doesn't look good in the README, which is what this bit of code is supposed to be (really nice README developer hook).

// Now instantiate the store!
const rootStore = RootStore.create({
  authors: [jamon],
  tweets: makeObservable([tweet])
});

@MarkLeMerise The reason we aren't using POJOs is we want to show how to create individual instances and then link them together.

jamonholmgren avatar Jul 09 '21 17:07 jamonholmgren

Hey @casamia918 - sorry we've still been taking a while on this one. As Jamon said, this is a bug. I'm going to label it as such, along with other tags to help folks prioritize and find issues to work on.

coolsoftwaretyler avatar Jun 28 '23 03:06 coolsoftwaretyler

I don't fully understand what to do at this point.

I can't simply copy and paste the example from this repo, since that results in a TS error. The above solutions also result in a TS error...

And looking at the website, all the examples have been removed from the repo as well.

Isn't there a simple, working example like the one in the repo?

tpotjj avatar Jul 25 '23 09:07 tpotjj

Hi @tpotjj - sorry about the confusion. We're in the process of shifting things around. We'll fix those links soon, but for now you can find the old examples over here:

  1. https://github.com/coolsoftwaretyler/mst-example-bookshop
  2. https://github.com/coolsoftwaretyler/mst-example-boxes
  3. https://github.com/coolsoftwaretyler/mst-example-todomvc
  4. https://github.com/coolsoftwaretyler/mst-example-redux-todomvc

I also have a quick CodeSandbox link that I like to use to start for examples: https://codesandbox.io/s/optimistic-swanson-vjpmyw. I tend to start here because it's more shareable/simpler than the full-fledged examples are.

Most of the code you see in this thread is a known issue, which is why we've marked it as a bug. However, the castToReferenceSnapshot solution from @casamia918 seems to work. Here's a working CodeSandbox with it: https://codesandbox.io/s/exciting-flower-y5q3p2?file=/src/index.ts

Full code looks like this:

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

// Define a couple models
const Author = types.model({
  id: types.identifier,
  firstName: types.string,
  lastName: types.string
});

const Tweet = types.model({
  id: types.identifier,
  author: types.reference(Author), // stores just the `id` reference!
  body: types.string,
  timestamp: types.number
});

// Define a store just like a model
const RootStore = types.model({
  authors: types.array(Author),
  tweets: types.array(Tweet)
});

// Instantiate a couple model instances
const jamon = Author.create({
  id: "jamon",
  firstName: "Jamon",
  lastName: "Holmgren"
});

const tweet = Tweet.create({
  id: "1",
  author: jamon.id, // just the ID needed here
  body: "Hello world!",
  timestamp: Date.now()
});

// Now instantiate the store!
const rootStore = RootStore.create({
  authors: [jamon],
  tweets: [castToReferenceSnapshot(tweet)]
});

It's not particularly ergonomic, but hopefully we'll get someone assigned to this issue in the future to get a better solution in place.

Does that help?

coolsoftwaretyler avatar Jul 25 '23 16:07 coolsoftwaretyler