mobx-state-tree icon indicating copy to clipboard operation
mobx-state-tree copied to clipboard

Add a way to dynamically drill down into type information

Open fbeaulieu opened this issue 6 years ago • 16 comments

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 !

fbeaulieu avatar Dec 14 '18 17:12 fbeaulieu

did you try getType(parentInstance.composedValue) === ComposedWithBaseModel? (assuming of course that parentInstance.composedValue is not undefined)

xaviergonz avatar Dec 14 '18 18:12 xaviergonz

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.

fbeaulieu avatar Dec 14 '18 19:12 fbeaulieu

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?

xaviergonz avatar Dec 14 '18 19:12 xaviergonz

Ho, it would be awesome, it would resolve my issue for sure !

fbeaulieu avatar Dec 14 '18 19:12 fbeaulieu

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

k-g-a avatar Dec 17 '18 12:12 k-g-a

What about

interface ITypeInfo {
  name: 'union' | 'array' | ...
  modelPropertyMembers? : IModelReflectionData,
  subTypes: { type: IType, info: IType Info}[] 
}

xaviergonz avatar Dec 17 '18 12:12 xaviergonz

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

xaviergonz avatar Dec 17 '18 12:12 xaviergonz

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.

k-g-a avatar Dec 17 '18 12:12 k-g-a

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?

k-g-a avatar Dec 17 '18 12:12 k-g-a

Ah, yep 😁

xaviergonz avatar Dec 17 '18 12:12 xaviergonz

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?

k-g-a avatar Dec 17 '18 12:12 k-g-a

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.

fbeaulieu avatar Dec 17 '18 13:12 fbeaulieu

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
        ]
      }
    }
  ]
}

xaviergonz avatar Dec 18 '18 18:12 xaviergonz

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

xaviergonz avatar Dec 18 '18 18:12 xaviergonz

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.

fbeaulieu avatar Dec 18 '18 19:12 fbeaulieu

can we make it recursively, but lazy, e.g. that subTypes is a getter?

mweststrate avatar Dec 19 '18 15:12 mweststrate