mobx-state-tree
mobx-state-tree copied to clipboard
Circular Dependency Issue - TS typings
Question
- [x] I've checked documentation and searched for existing issues
- [x] I tried the spectrum channel
Following a lot of hours of research, I ran into this: https://github.com/mobxjs/mst-gql/pull/140. Tested it in my codebase and it's finally a 'sort' of fix for the typings on circular dependencies.
Are you guys considering including it in MST ?!
Posted this from my phone, I'll update it further when I get home.
So coming back to this, for dealing with circular references, an idea - copying most of it from @godness84
const MyModel = types.model(
refExample1: types.reference(types.late((): any => RefExample1)),
refExample2: types.reference(types.late((): any => RefExample2)),
refExample3: types.array(types.reference(types.late((): any => RefExample3))),
);
type Without<T, K> = Pick<T, Exclude<keyof T, K>>;
// this needs better typing
type ExtendRefs<K> = {
[P in keyof K]: null extends K[P]
? never
: K[P] extends IArrayType<infer O>
? IMSTArray<Instance<IReferenceType<O>>>
: K[P] extends IAnyComplexType
? Instance<IReferenceType<K[P]>>
: never;
};
type WithRefsModelType<T extends IAnyModelType, OTHERS> = Instance<
T extends IModelType<infer P, infer O, infer C, infer S>
? IModelType<Without<P, keyof OTHERS>, O & ExtendRefs<OTHERS>, C, S>
: never
>;
interface IRefs {
refExample1: typeof RefExample1;
refExample2: typeof RefExample2;
refExample3: IArrayType<typeof RefExample3>;
}
export type IMyModelType = WithRefsModelType<typeof MyModel, IRefs>;
Maybe someone with more TS knowledge can build on this and provide it as an API in MST ?
Tagging in @mweststrate cause I think he followed the mst-gql issue as well
Sorry, could you summarize it without referring to an entire thread? Note that in MST there is no code generation unlike in mst-gql, so the options are a bit more limited, as we need to have TS infer the types, rather than generating them.
Sorry, basically they added a solution to their generator to better provide types on circular dependencies without typescript blowing up
const MyModel = types.model(
// this blows up in TypeScript if RefExample1 references MyModel - circular dependencies
refExample1: types.reference(types.late((): Instance<typeof RefExample1> => RefExample1)),
refExample2: types.reference(types.late((): any => RefExample2)),
refExample3: types.array(types.reference(types.late((): any => RefExample3))),
);
With the above I'm thinking if somehow we can integrate something in MST's API like
import { Instance, IModelType, IMSTArray, IReferenceType, IAnyComplexType, IArrayType } from 'mobx-state-tree';
type Without<T, K> = Pick<T, Exclude<keyof T, K>>;
// this needs better typing and only covers array/instance reference
type ExtendRefs<K> = {
[P in keyof K]: null extends K[P]
? never
: K[P] extends IArrayType<infer O>
? IMSTArray<Instance<IReferenceType<O>>>
: K[P] extends IAnyComplexType
? Instance<IReferenceType<K[P]>>
: never;
};
type WithRefsModelType<T extends IAnyModelType, OTHERS> = T extends IModelType<
infer P,
infer O,
infer C,
infer S
>
? IModelType<Without<P, keyof OTHERS>, ExtendRefs<OTHERS> & O, C, S>
: never;
To provide better typings for these circular references
In the example above we can do
interface IRefs {
refExample1: typeof RefExample1;
refExample2: typeof RefExample2;
refExample3: IArrayType<typeof RefExample3>;
}
export interface IMyModelType extends Instance<WithRefsModelType<typeof MyModel, IRefs>> {};
And then in actions for example or where the instance is used
MyModel.actions(self => {
const _self = self as IMyModelType;
// solution now is (_self.refExample1 as IExample1Instance).stuff
_self.refExample1.stuff // this now has typings on circular deps without having to cast it
})
I hope @xaviergonz not gonna mind linking him but I've seen he worked a lot on the TS/typings for MST :)
@oviava This seems really cool, do you have any update on that? Have you used it yourself in a project? Any pros/cons?
Hey @oviava - it's been a while since we heard from you on this MST thread, but I know we're actively looking to improve our TS here. Are you interested in exploring this any more?
I'm going to put the TS label on this issue for now, and happy to talk about if/when/how to move it forward.