Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cast TS error when types.array sub-type has reference #1640

Open
3 tasks done
Ayub-Begimkulov opened this issue Jan 16, 2021 · 2 comments
Open
3 tasks done

cast TS error when types.array sub-type has reference #1640

Ayub-Begimkulov opened this issue Jan 16, 2021 · 2 comments
Labels
Typescript Issue related to Typescript typings

Comments

@Ayub-Begimkulov
Copy link

Bug report

  • I've checked documentation and searched for existing issues
  • I've made sure my project is based on the latest MST version
  • Fork this code sandbox.

Sandbox link or minimal reproduction code

import { cast, Instance, types } from "mobx-state-tree";
import { v4 as uuid } from "uuid";

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

interface IReference extends Instance<typeof Reference> {}

const Entity = types.model("Entity", {
  id: types.identifier,
  name: types.string,
  ref: types.reference(Reference)
});

interface IEntity extends Instance<typeof Entity> {}

const RootModel = types
  .model("Store", {
    entities: types.array(Entity),
    references: types.array(Reference)
  })
  .actions((self) => ({
    setReferences(references: IReference[]) {
      // no references in the `Reference` model
      // so it works correctly
      self.references = cast(references);
    },
    setEntities(entities: IEntity[]) {
      // `Entity` model has a reference
      // so the cast isn't working
      self.entities = cast(entities);
    }
  }));

Describe the expected behavior

self.entities = cast(entities) should not have any typescript errors

Describe the observed behavior

TypeScript error:
Type '{ id: string; name: string; } & NonEmptyObject & IStateTreeNode<IReferenceType<IModelType<{ id: ISimpleType<string>; name: ISimpleType<string>; }, {}, _NotCustomized, _NotCustomized>>>' is not assignable to type 'ReferenceIdentifier'

@taylorcjohnson taylorcjohnson added the Typescript Issue related to Typescript typings label Jan 17, 2021
@iChenLei
Copy link
Member

castToSnapshot

castToSnapshot(snapshotOrInstance: I): Extract<I, IAnyStateTreeNode> extends never ? I : TypeOfValue["CreationType"]

In your reproduction example, replace cast with castToSnapshot:

setEntities(entities: IEntity[]) {
  // `Entity` model has a reference
  // so the cast isn't working
-  self.entities = cast(entities);
+  self.entities = castToSnapshot(entities);
}

looks like everything work fine!

MST castToSnapshot doc: https://mobx-state-tree.js.org/API/index#casttosnapshot

Defined in packages/mobx-state-tree/src/core/mst-operations.ts:941
Casts a node instance type to an snapshot type so it can be assigned to a type snapshot (e.g. to be used inside a create call). Note that this is just a cast for the type system, this is, it won't actually convert an instance to a snapshot, but just fool typescript into thinking so.

I am not a MST expert, so I don't know why it's work. Maybe Maintainer @jamonholmgren can explain explicitly.

@thegedge
Copy link
Collaborator

thegedge commented Jul 6, 2024

So this is tricky. self.entities is an IMSTArray, and you definitely can't assign a regular array to an IMSTArray, but MST technically does support this.

castToSnapshot works here, but it's not super helpful because it's actually just turning the right-hand side into never, which you can assign to whatever. I would probably just do this for now:

(self as any).entities = entities;

or you could do something like this:

type T = {
  get entities(): typeof self.entities
  set entities(v: (Instance<typeof RootModel> | SnapshotIn<typeof RootModel>)["entities"])
}

(self as T).entities = entities

I believe that's the "true" type of self in that scenario.

Once microsoft/TypeScript#43826 is resolved, we can generate the getter and setter types, like in T above :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Typescript Issue related to Typescript typings
Projects
None yet
Development

No branches or pull requests

4 participants