Mobx-state-tree: Typesafe model env

Created on 7 Oct 2017  路  9Comments  路  Source: mobxjs/mobx-state-tree

I know there has already been a related issue raised and fixed around typesafety in https://github.com/mobxjs/mobx-state-tree/issues/250

My question however is related but different.

Would it be possible to specify on the model the environment that it expects? For example:

interface ITodoEnv
{
    logger: ILogger
}

const Todo = types.model<ITodoEnv>({
    title: ""
})
.actions(self => ({
    setTitle(newTitle) {
        // grab injected logger and log
        getEnv(self).logger.log("Changed title to: " + newTitle)
        self.title = newTitle
    }
}))

I know that we can currently do getEnv<ITodoEnv>(self).logger but because we have manually defined what we expect the environment to contain at the model level 'getEnv(self).logger' then becomes typesafe throught the entire model without having to retype is each time?

Most helpful comment

I understand it, but we also can check this type in model time.
With proper typings it would be impossible to connect models with different env type.
So root model and all its submodels has to have the same env type by design or any type by default.

All 9 comments

Or if not that, perhaps this is better:

const Todo = types.model({
    title: ""
})
.withEnv({
    logger: types.optional(Logger)
})
.actions(self => ({
    setTitle(newTitle) {
        // grab injected logger and log
        getEnv(self).logger.log("Changed title to: " + newTitle)
        self.title = newTitle
    }
}))

Could a view accomplish this?

I dont think so... using ShopStore as an example:
https://github.com/mobxjs/mobx-state-tree/blob/master/examples/bookshop/src/stores/ShopStore.js

...
.views(self => ({
        get fetch() {
            return getEnv(self).fetch
        },
...

getEnv(self).fetch is not typesafe, so you have just moved the issue elsewhere.

Ghetto typing it with as would make your callsites nicer, but ya, I gotcha. I like what you鈥檙e after here. 馃憤

If we make the getEnv() strongly typed via the example I provided above, im thinking that the whole tree's getEnv() could be made strongly typed too...

But im sure this has already been considered and dismissed before.

I'll add my 5 cents here.
Currently, we are using another MST store as default environment for models.
With that we have to wrap getEnv in another function just for typings:

function getAppEnv(model: IStateTreeNode): IGlobalEnvironment {
    return getEnv<IGlobalEnvironment>(model);
}

And we use it everywhere. And this is somewhat _hacky_ solution, i think.
I agree with @mikecann and vote for some kind of strong typing the environment also.
This must be totally optional, as it is overhead for the most of solutions.
But for the team of 10+ junior devs it is really needed.

The problem with strongly typing env in models is that it will be a wrong assumption exactly like casting getEnv to a type is. Env is exactly like react context is, and any is its perfect nature.
env cames from the root, so this means that env will change over time based on which is the current root element of the tree.

I understand it, but we also can check this type in model time.
With proper typings it would be impossible to connect models with different env type.
So root model and all its submodels has to have the same env type by design or any type by default.

Won't fix, I don't see any way in which getEnv can now what type it will be returning based on the type of the type of the thing you pass in. Which can not know the type of it's environment either (generically speaking) because only the root knows about the type, and a type can potentially have any other model type as parent or root. The type system cannot infer here in the generic case; the same Todo model could be used by two different parent models, which both have their own environment specification(s) etc....

Was this page helpful?
0 / 5 - 0 ratings