I have 2 classes like so.
export class Risk {
... other properties
mitigations?: Mitigation[] = [];
}
and
export class Mitigation {
... other properties
risks?: Risk[] = [];
}
I understand we should never do this, as this is circular dependency. The problem is, this is the reality. We're using neo4j, and can get back Risk
with Mitigations
, or a Mitigation
with Risks
.
How do I approach this case?
CodePudding user response:
You can use interfaces instead of a class. Interfaces don't have implementation details, so there's no risk of creating a circular dependency between two interfaces:
export interface IRisk {
// other properties
mitigations?: IMitigation[]
}
export interface IMitigation {
// other properties
risks?: IRisk[]
}
Then, in your implementation files (e.g. risk.ts and mitigation.ts), you can implement the interfaces like this:
// risk.ts
import { IRisk, IMitigation } from './interfaces'
export class Risk implements IRisk {
// implementation details
mitigations?: IMitigation[] = []
}
// mitigation.ts
import { IRisk, IMitigation } from './interfaces'
export class Mitigation implements IMitigation {
// implementation details
risks?: IRisk[] = []
}
CodePudding user response:
"I understand we should never do this, as this is circular dependency"
No, such arrangement can be described as mutually recursive. It's a very powerful technique and completely valid in typescript -
type Actor = {
name: string,
movies: Array<Movie>
}
type Movie = {
title: string,
actors: Array<Actor>
}
type Branch<T> = {
data: T,
children: Tree<T>
}
type Tree<T> = Array<Branch<T>>
There are many such relationships that are mutually recursive. You shouldn't avoid them based on a narrow understanding that it's the same as a circular dependency.
Mutually recursive datum can be effectively processed using mutually recursive procedures. If you are interested, I have written many posts on the topic.