-
Notifications
You must be signed in to change notification settings - Fork 120
Dealing with circular dependencies #332
Description
Version
2.4.0
Case
When defining model it isn't unusual to have a recursive structure, where one type circularly depends on another type.
Consider this:
Each Entity requires to have information about Place, where it belongs. But each Place is an Entity.
Thus, we have a circular dependency:
// entity.js
import Place from './place'
export const Entity = t.interface({
place: Place
})// place.js
import Entity from './entity'
export const Place = Entity.extend({})Seems like there is no way to express such a relationship with tcomb, and current tcomb tooling makes it impossible to workaround.
Thoughts
Issue isn't related to the tcomb itself and rather a technical limitation of current modules implementation, but I found myself struggling to work around that issue with tcomb tools.
The root of the issue is that all tcomb declarations are "eager". They evaluated as soon as module loaded, and because another module isn't resolved yet either place.js will complain that it can't extend undefined (Entity which isn't loaded yet), or entity.js will complain that its interface declaration is faulty (because Place ends up undefined).
So, it feels like there should be a way to make type evaluation "lazy" — to force it to evaluate when used (and by that time in most case all variables should resolve), and not when declared. However, it means that meta information won't be available statically on type...
t.declare('Type') and Type.define doesn't help here much too, since it will be in same way eagerly evaluated and end up with broken types. Or maybe I'm missing obvious way how it helps in such situations?
I think maybe it could help if define could accept a function rather than a type definition.
However, to be honest, I wasn't able to come up with a good solution yet. Maybe someone knows the solution.