mobx-state-tree
mobx-state-tree copied to clipboard
Add a way to dynamically drill down into type information
To be able to know at runtime, if a property type is composed from a specific Model
Is this possible at runtime, to know if a property type is a type composed from a specific model/type using a method like getType, since if the property if of a specific type, I would be able to handle this differently...
Let's say I have the following code:
const ComposedWithBaseModel = types .compose( BaseModel, // Any custom model created with types.model... types.model({ myValue: '' }) ) .named('ComposedWithBaseModel');
const ParentModel = types.model({ anyValue: '', composedValue: types.maybe(types.reference(ComposedWithBaseModel)) });
var parentInstance = ParentModel.create({anyValue: '', ComposedValue: ....});
At runtime, I'd want to be able to check if the property "composedValue" is of a type that is composed with 'ComposedWithBaseModel' (whether from parentInstance ParentModel itself).
I've tried hasParentOfType but didn't work. I've tried to drill down with getType(parentInstance.composedValue) but didn't figured out a "scientific" way of discovering if composedValue had ComposedWithBaseModel type in its hierarchy...
Any thought/idea/solution ?
thanx !
did you try getType(parentInstance.composedValue) === ComposedWithBaseModel
?
(assuming of course that parentInstance.composedValue is not undefined)
did you try
getType(parentInstance.composedValue) === ComposedWithBaseModel
? (assuming of course that parentInstance.composedValue is not undefined)
Yes, actually, getType returns an object from which we can grab some of the type meta data like the name, the property list, etc. but I don't find any place where I could tap on to get the "structure" of the underlying type (here it gives me a type name of "ComposedWithBasedModel", so I just get the first level of type composition. I didn't succeed to drill down (using the object returned by getType(...)) to the model composition where I could see some kind of an array of type name like ['BaseModel', 'anonymous/or named type']...
Don't know if I could work around using another mst API...
fab.
Ah, I don't think that's saved anywhere it could be saved and then offered through an API like
getTypeInfo(someType): {
subTypes: IType[]
name: 'union' | 'array' | ...
... e.g. defaultValue for optional
}
// subTypes is:
// for composed types an array with the composed types
// for array the type passed to array as a single array item
// for map the type passed to map as a single array item
// for reference the referenced type
// for maybe/maybeNull the "maybed" type
// for late the resolved late type
// for refinement the refined type
// for optional the optional type
// for union the unioned types
// etc.
or alternatively someType.getInfo()
@mweststrate @k-g-a thoughts?
Ho, it would be awesome, it would resolve my issue for sure !
getTypeInfo
approach seems more consistent with current reflection API (getrPropertyMembers
, getMembers
).
I'd modify returned value just a little bit to match the following interface:
interface ITypeInfo {
name: 'union' | 'array' | ...
type: IType,
members: IModelReflectionData,
subTypes: ITypeInfo[]
}
So the returned information is sufficient for any pupose. Otherwise, user will have to manually process subTypes
.
EIDT: ITypeInfo.type was typed as IType[]
by mistake
What about
interface ITypeInfo {
name: 'union' | 'array' | ...
modelPropertyMembers? : IModelReflectionData,
subTypes: { type: IType, info: IType Info}[]
}
Sadly to get all the model members an actual instance is required due to lazy instantiation, so the best that can be done is getting the props
What about
Yep, seems nice. I thought getTypeInfo
recieves node as argument, but it recieves a type, so user already has it, no need to include.
Sadly to get all the model members an actual instance is required due to lazy instantiation, so the best that can be done is getting the props
So modelPropertyMembers
whould be IModelReflectionPropertiesData
, not IModelReflectionData
, right?
Ah, yep 😁
BTW, internally we use same cloneAndEnhance
for compose
as for props
/actions
/views
etc.
The question is: will we include types, generated by actions
/views
etc. calls into subTypes
or only compose
ones?
What about
interface ITypeInfo { name: 'union' | 'array' | ... modelPropertyMembers? : IModelReflectionData, subTypes: { type: IType, info: IType Info}[] }
Just wondering, I guess the subTypes collection would contain only the first level of the type composition right ? (not a recursive type resolution)
And as well, would the subTypes still contain compositions if for instance, my property is of type: types.maybe(types.reference(types.late(()=>MyComposedType))) ?
fab.
It would be recursive.
types.maybe(types.reference(types.late(()=>MyComposedType))) ?
That'd map to
{
name: "maybe",
subTypes: [
{
type: types.reference(types.late(()=>MyComposedType)),
info: {
name: "refrence",
subTypes: [
...etc
]
}
}
]
}
We have to be careful with circular references though, so we should keep a map inside the function with the already parsed type infos and return those already parsed objects
We have to be careful with circular references though, so we should keep a map inside the function with the already parsed type infos and return those already parsed objects
Yes, makes sense and I would totally agree to drill down my self recursively into subTypes even if subTypes would expose only the first level of "parent types" if this is more simple/performent for you to implement.
can we make it recursively, but lazy, e.g. that subTypes
is a getter?