Búsqueda de sitios web

Typescript - Determinar si un tipo genérico cumple con interfaces adicionales, genéricamente restringidas


Estoy tratando de crear un sistema en el que una clase genérica de representación de matrices pueda operar sobre diferentes tipos de valores de matriz, donde algunos de esos tipos tienen algunas de sus propias restricciones genéricas. Hasta ahora, la mejor manera de escribir el enfoque que he tomado en código es:

interface MatrixValue {
  readonly coords: [number, number]
}

interface LinkedValue<T extends LinkedValue<T>> extends MatrixValue {
  antecedents(): T[]
  derivatives(): T[]
}

class MatrixViz<T extends MatrixValue>{}

Podría ser capaz de salirme con la mía usando tipos polimórficos de this para LinkedValue, pero en este momento prefiero no hacerlo, ya que el paradigma general aquí es de familias de tipos de valor de matriz, y cualquier instancia de MatrixViz es genérica con respecto a la familia, no a un tipo individual en ella. Por lo tanto, un método de LinkedValue debería poder retornar cualquier otro dentro de la familia, no solo this.

Donde estoy teniendo problemas es dentro de la clase MatrixViz, cuando necesito averiguar si T es simplemente un MatrixValue, o realmente un LinkedValue, para poder habilitar funcionalidades adicionales para LinkedValue. Según entiendo (esta es mi primera incursión con TypeScript) esto es algo para lo que debería escribir un guardia de tipo definido por el usuario. Parece probable que necesite usar el patrón de constructor de clase en un método de MatrixViz, pero no estoy seguro de cómo abordar eso, dado que además necesito restringir el tipo al T del MatrixViz.

¡O tal vez hay una mejor manera de representar esto que con la herencia de interfaces! Abierto a casi cualquier cosa.

Actualización: resultado de ejemplo

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

Básicamente, cada instancia de MatrixValue representa un borde en un grafo bipartito. El MatrixViz, al ser una matriz, está representando un aspecto principal del grafo como coordenadas x e y. Pero también hay otras dimensiones - antecedentes, derivados - que pueden conectar bordes con otros bordes. Por ejemplo, todas las instancias de DOWN tendrán un antecedente USE; correspondientemente, algunas instancias de USE tendrán derivados DOWN.

quiero que la implementación genérica MatrixViz<T> pueda implementar una representación visual general de la relación antecedente/derivada cuando tenga un T que incluya tales relaciones, pero simplemente omitir esas visualizaciones cuando no lo tenga.