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

getType ignore types.refinement

Open swayf opened this issue 5 years ago • 3 comments

Bug report

  • [x] I've checked documentation and searched for existing issues may be somehow dependent on https://github.com/mobxjs/mobx-state-tree/issues/1114 ?
  • [x] I've made sure my project is based on the latest MST version
  • [x] Fork this code sandbox or another minimal reproduction.

Sandbox link or minimal reproduction code

https://codesandbox.io/s/mobx-state-tree-todolist-52jt7

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

const TestType = types.model("TestType", {
  test1: types.number,
  test2: types.number
});

const TestType2 = types.refinement(
  "TestType2",
  TestType,
  value => value.test1 + value.test2 === 100
);
const testModel2 = TestType2.create({ test1: 50, test2: 50 });

try {
  const testModel2Fail = TestType2.create({ test1: 50, test2: 40 });
} catch (e) {
  console.log("OK");
}

const test = getType(testModel2).create({ test1: 50, test2: 40 }); // should fail

Describe the expected behavior

last expression should fail (or?)

Describe the observed behavior

but it does not, because getType returns type before refinement

swayf avatar Aug 16 '19 11:08 swayf

That's because upon ".create", the refinement (validation) is run first, then it will instantiate that node as type "TestType", so getType will return that as type for that node. To fix this the refinement would need to be kept as type for the node (doable, but not easy).

xaviergonz avatar Sep 21 '19 21:09 xaviergonz

Not sure if a bug or an enhancement :)

xaviergonz avatar Sep 21 '19 21:09 xaviergonz

We've found that you can use types.compose to change the name of the refined model, which doesn't help with dynamically creating new instances but does allow us to reflect on the type of a model created from a snapshot:

const TestType2 = types.refinement(
  types.compose("TestType2", TestType),
  value => value.test1 + value.test2 === 100
);
const testModel2 = TestType2.create({ test1: 50, test2: 50 });
getType(testModel2).name; // 'TestType2'

Using types.compose with just one model feels hacky, but that code does seem to work.

eatyourgreens avatar Mar 01 '23 13:03 eatyourgreens