I'm trying to create a system in which a generic matrix rendering class can operate over different types of matrix values, where some of those types have some of their own generic constraints. It's by far write out the approach i've taken thus far in code:
interface MatrixValue {
readonly coords: [number, number]
}
interface LinkedValue<T extends LinkedValue<T>> extends MatrixValue {
antecedents(): T[]
derivatives(): T[]
}
class MatrixViz<T extends MatrixValue>{}
i might be able to get away with polymorphic this types for LinkedValue, but at this point i'd rather not, as the general paradigm here is of families of matrix value types, and any MatrixViz instance is generic with respect to the family, not any individual type in it. Thus, a LinkedValue method should be able to return anything else in the family - not just this.
Where i'm running into trouble is within the MatrixViz class, when i need to figure out if T is merely a MatrixValue, or actually a LinkedValue, so that i can enable additional functionality for LinkedValue. AIUI (This is my first foray with typescript) this is something i should write a custom user-defined type guard for. It seems likely i'll need to use the class constructor pattern in a MatrixViz method, but i'm not sure how to approach that, given that i need to additionally constrain the type to the T of the MatrixViz.
Or, maybe there's a better way to represent this than with interface inheritance! Open to most anything.
Update: example result
// A interface describing a family of LinkedValue that can return each other
interface DegreeAssignment {
readonly coords: [number, number]
antecedents(): DegreeAssignment[]
derivatives(): DegreeAssignment[]
/* Other, domain-specific props */
summary(): string
nameCoords(): [string, string]
}
class USE implements DegreeAssignment, LinkedValue<DegreeAssignment> {}
class UPX implements DegreeAssignment, LinkedValue<DegreeAssignment> {}
class DOWN implements DegreeAssignment, LinkedValue<DegreeAssignment> {}
// Contrast all these DegreeAssignments with this, a simple MatrixValue
// impl. Here, there's no family of types, just the one class.
class SelectabilityAssignment implements MatrixValue {
readonly coords: [number, number]
}
Basically, each instance of MatrixValue represents an edge in a bipartite graph. The MatrixViz, being a matrix, is representing one, primary aspect of the graph as x and y coordinates. But there's also other dimensions - antecedents, derivatives - that may link edges to other edges. For example, all instances of DOWN, will have a USE antecedent; correspondingly, some instances of USE will have DOWN derivatives.
i want the MatrixViz<T> generic implementation to be able to implement a general visual representation of the antecedent/derivative relation when it has a T that includes such relations, but just omit those visuals when it doesn't.