Я пытался реализовать графоподобную структуру данных в машинописном тексте и с трудом сохранял ее тип, после многих решений я пришел к этому:
interface Cities {
lisbon: any
porto: any
faro: any
}
class Graph<T> {
adjacencyList: {
[K in keyof T]?: (keyof T)[]
} = {}
addVertex(value: keyof T) {
if (!this.adjacencyList[value]) this.adjacencyList[value] = []
}
addEdge(vertex1: keyof T, vertex2: keyof T) {
this.adjacencyList[vertex1]?.push(vertex2)
this.adjacencyList[vertex2]?.push(vertex1)
}
}
есть ли более элегантный способ сделать это? Я хотел использовать дженерики, чтобы быть более универсальным. Возможно ли что-то подобное?
enum Cities {
"lisbon",
"porto",
"faro"
}
class Graph<T> {
adjacencyList: {
[K in T]?: T[]
} = {}
addVertex(value: T) {
if (!this.adjacencyList[value]) this.adjacencyList[value] = []
}
addEdge(vertex1: T, vertex2: T) {
this.adjacencyList[vertex1]?.push(vertex2)
this.adjacencyList[vertex2]?.push(vertex1)
}
}
говорит, что T не может быть назначен символу типа...
Это потому, что машинописный текст не гарантирует, что все значения в T
на самом деле будут строками, числами или символами (единственные допустимые ключи объекта с точки зрения машинописного текста). Подумайте о том, что произойдет, если вы будете кормить number[]
как T
. Итак, добавьте пункт, который он должен расширять string | number | symbol
:
class Graph<T extends string | number | symbol> {
adjacencyList: {
[K in T]?: T[]
} = {}
addVertex(value: T) {
if (!this.adjacencyList[value]) this.adjacencyList[value] = []
}
addEdge(vertex1: T, vertex2: T) {
this.adjacencyList[vertex1]?.push(vertex2)
this.adjacencyList[vertex2]?.push(vertex1)
}
}
Затем, чтобы передать ему перечисление, используйте keyof typeof Enum
, чтобы получить тип объединения, состоящий из всех возможных строк:
const foo = new Graph<keyof typeof Cities>();