I have some issue with explicit model typing in v3.
I need to get model with self reference with typescript.
There is solution https://github.com/mobxjs/mobx-state-tree/issues/417 for MST v2 smth. like that:
interface IModel {
key: string;
reference: IModel;
prop: number;
}
export const Model: IModelType<ISnapshottable<IModel>, IModel> = types.model({
key: types.identifier,
reference: types.late(() => Model),
prop: types.number
})
What is a proper way to express model type with MST v3?
The only ugly way I was able to do this is there:
import {
types, IModelType, IComplexType
} from 'mobx-state-tree';
const ModelProps = {
key: types.identifier,
num: types.number,
ref: types.frozen() as IComplexType<IModel | string | number, string | number, IModel>,
};
interface IModel {
method: (param: number) => string,
key: string,
num: number,
ref: IModel,
}
export const Model: IModelType<typeof ModelProps, IModel> = types.model({
...ModelProps,
ref: types.reference(types.late(() => Model))
})
.actions(self => ({
method: (t: number) => { return t.toString(); }
}))
export const m = Model.create({
key: '1',
num: 0,
ref: '1'
});
Another aproach is to manualy resolve references.
Still waiting for comments.
import {
types, getRoot, resolveIdentifier
} from 'mobx-state-tree';
export const Model = types.model(
{
key: types.identifier,
num: types.number,
refKey: types.string
})
.views(self => ({
get ref() {
const root = getRoot(self);
const ref = resolveIdentifier(Model , root, self.refKey);
return ref as typeof Model.Type;
}
}))
.actions(self => ({
method: (t: number) => {
return t.toString();
}
}))
export const m = Model.create({
key: '1',
num: 0,
refKey: '1'
});
Could you create a TS based code sandbox so that others can chime in?
Op di 24 jul. 2018 09:44 schreef AndrewSorokin notifications@github.com:
Another aproach is to manualy resolve references.
Still waiting for comments.
import {
types, getRoot, resolveIdentifier
} from 'mobx-state-tree';export const Model = types.model(
{
key: types.identifier,
num: types.number,
refKey: types.string
})
.views(self => ({
get ref() {
const root = getRoot(self);
const ref = resolveIdentifier(Model , root, self.refKey);
return ref as typeof Model.Type;
}
}))
.actions(self => ({
method: (t: number) => {
return t.toString();
}
}))export const m = Model.create({
key: '1',
num: 0,
refKey: '1'
});—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/mobxjs/mobx-state-tree/issues/943#issuecomment-407312951,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABvGhL5o3OyaQ52lkvEcjfxsBV8nQsM5ks5uJtBJgaJpZM4Vagl_
.
Sure, here is it.
Example with manual reference resolution
https://codesandbox.io/s/20wlz7256j
I don't like that because of redundancy and some extra work I need to do.
Example with explicit typings:
https://codesandbox.io/s/jl5jkywyk3
It looks a bit ugly.
Is there any more elegant way to explicilly define model type with self reference?
There seems to be no clean way to fix, as TS really can't handle the type of something self referring. Even upcasting doesn't work. However, using a temporary variable seems to work around it:
let tmp: any
/// BrokenTypingsModel has any type or leads to TS compiler error
const BrokenTypingsModel = types.model({
key: types.identifier,
brokenRef: types.maybe(types.reference(types.late<BrokenTypeLike, BrokenTypeLike, BrokenTypeLike>(() => tmp)))
})
interface BrokenTypeLike {
key: string
brokenRef: BrokenTypeLike
}
tmp = BrokenTypingsModel
const b = BrokenTypingsModel.create({ key: '3' })
console.log(b.brokenRef ? b.brokenRef.key : 'nothing')
Is the problem described here similar to the one described in this issue?
@bourquep no that is a different problem, the issue here is like expressing a self-referring structure interface Node { children: Node[] }. However, the issue you are referring to is actions that refer to their own structural type, which we can express because models are built up in parts (and actions can be defined in local closures first) as described here (not ideal, but possible): https://github.com/mobxjs/mobx-state-tree#typing-self-in-actions-and-views)
Closing as a can't fix at this moment :-(
actually using 'this' for actions defined in the same scope is also possible (like for views), maybe the readme should be updated with that?
Hmm yes that might be outdated indeed
Op ma 27 aug. 2018 om 19:47 schreef Javier Gonzalez <
[email protected]>:
actually using 'this' for actions defined in the same scope is also
possible (like for views), maybe the readme should be updated with that?—
You are receiving this because you modified the open/close state.Reply to this email directly, view it on GitHub
https://github.com/mobxjs/mobx-state-tree/issues/943#issuecomment-416309485,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABvGhHkJY0gpYYr25zbXKCQnUa4p9SApks5uVDDLgaJpZM4Vagl_
.
I'm having trouble getting the workarounds using late working in newer versions, and the code sandbox examples also don't seem to work with newer versions.
That said, there seems to be a couple of new solutions for circular references using conditional types. See This Comment and this Comment in the TypeScript repo. Would either of these be applicable here?
I can confirm late is broken in TS. At least I didn't found any solution how to properly typesafe. Even inline docs doesn't work https://github.com/mobxjs/mobx-state-tree/blob/f62fe87c9dd7c1655242e4511d921e4858cf8756/packages/mobx-state-tree/src/types/utility-types/late.ts#L104
I'm not sure if you are using late to fix cicular/self-references, but if so, from the docs:
If you are using TypeScript and you get errors about circular or self-referencing types then you can partially fix it by doing:
const Node = types.model({
x: 5, // as an example
me: types.maybe(types.late((): IAnyModelType => Node))
})
In this case, while "me" will become any, any other properties (such as x) will be strongly typed, so you can typecast the self referencing properties (me in this case) once more to get typings. For example:
node.((me) as Instance<typeof Node>).x // x here will be number
thanks @xaviergonz I hoped there will be a better way. I end up using views
const Node = types.model({
x: 5,
me: types.maybe(types.late((): IAnyModelType => Node))
}).views( self => ({
get meProp() {
return self.me as Instance<typeof Node>;
}
}))
Nice trick! Never thought of adding a view afterwards to actually make its type proper again!
Worth adding this trick to TS FAQ
@elie222 PR welcome!
Sure. Just had a look here and I see the Edit on GitHub link is broken:
https://mobx-state-tree.gitbook.io/docs/faq
Where is the repo for these docs?
Sorry, will just update the official README
Ah. I see it's already there :)
https://github.com/mobxjs/mobx-state-tree/blob/master/docs/API/README.md#late
some possible solution:
var User = struct({
user: () => User,
});
User.user.user.user // ok
function struct<T>(obj: T) {
return obj as {[P in keyof T]: T[P] extends () => infer R ? R : T[P]};
}
@kresli Isn't it results in the same error about the self-referenced variable? It's still part of the same declaration, so TS will complain that it can't infer its type, even despite it's in a views clause
@ArmorDarks No it shouldn't because the model part would complain about circulation. So in the getter you would type model where me prop in model is any. therefor there is no circulation.
Please don't reply on closed issues
Most helpful comment
thanks @xaviergonz I hoped there will be a better way. I end up using views