Spectrum is now read-only. Learn more about the decision in our official announcement.


Opinionated, transactional, MobX powered state container combining the best features of the immutable and mutable world for an optimal DX


Generic set action in Typescript

July 21, 2019 at 7:11pm
The mobx-state-tree community has a new home. This thread is preserved for historical purposes. The content of this conversation may be innaccurrate or out of date. Go to new community home →

Generic set action in Typescript

July 21, 2019 at 7:11pm
Hi, does anybody know how to make something like this work? For quickly prototyping it would be nice to have a typesafe set method.
import { Instance, types } from 'mobx-state-tree';
const storeFields = types.model({
text: types.string,
number: types.number,
bool: types.boolean
type IStoreFields = Instance<typeof storeFields>;
const store = storeFields.actions(self => ({
set(key: keyof IStoreFields, value: IStoreFields[typeof key]) {
self[key] = value; // TS-Error: Cannot assign to '[$stateTreeNodeType]' because it is a read-only property
In JS it's no problem until it explodes at runtime because of an invalid combination of key and value.

July 21, 2019 at 9:27pm
You can use Object.assign(self, { [key]: value, }). However, Object.assign's return types are surprising: Personally I stopped using Object.assign for this very reason and I prefer strongly typed individual setters. Here's one way to do it:
set({ text = self.text, number = self.number, bool = self.bool, }) {
self.text = text
self.number = number
self.bool = bool
Yes, it is verbose and repetitive, which sucks. But at least it is type safe.

November 29, 2019 at 10:45am
Hi , i was facing the same issue and i could solve your "read-only" error, simply by using type IStoreFields = SnapshotIn<typeof storeFields>; instead of "Instance"
interesting. Which typescript version do you use? And what are your settings in your tsconfig?
Because I tried to replicate this and got this error
i double checked my test case and it seems to make a difference if the model has a single type of types (eg: types.string) or different ones, like in your sandbox.
i created a sandbox on my own and tried to figure it out and it seems to work now for multiple types. take a look and tell me if this may fix your problem:
for the tsconfig i added the recommended flags from mst
Hi, thanks for replying
But this solutions looses the type safety. I added a test where one provides the wrong type and typescript can't catch it anymore.
Impressive. I like it very much.

November 30, 2019 at 4:05am
This is awesome! I've been avoiding Object.assign because it isn't typesafe, but with this approach we can use it:
setUserDetails(userDetailsToSet: Partial<SnapshotIn<typeof self>>) {
Object.assign(self, userDetailsToSet)
We should PR it to the docs :)

November 30, 2019 at 12:11pm
, do you want to write about it? Else I would write a blog post about it and of course give credit to you and link to this discussion.

December 2, 2019 at 8:58am
feel free to write your blogpost. credit would be awesome ;)

December 5, 2019 at 3:49pm
And there was another issue. Your solution didn't support optional types. I managed to use it with SnapshotIn but had to tell Typescript to ignore the line self[key] = value

December 7, 2019 at 7:29am
what happens if you switch back from SnapshotIn to Instance?

December 8, 2019 at 8:09am
The problem is in the types.optional- it accept a string or undefined but will be inferred as only string. Of SnapshotIn, SnpshotOut and Instance only SnapshotIn describes the types to set something correctly.
This looks a little bit less brute force:
.actions(self => ({
K extends keyof SnapshotIn<typeof self>,
T extends SnapshotIn<typeof self>
>(key: K, value: T[K]) {
self[key] = value as any;
ah i see ... i think any should never be a solution for something. seems like if we "cast" the value it allows types.optional to be undefined.
Great, wasn't aware of cast :)
Even if it as basically the same. We tell the compiler, it's okay.

February 3, 2020 at 3:18pm
Hi, finally managed to write the article about it

November 5, 2020 at 8:10am
This is great! I was searching for this. Thank you very much and .