问题描述
我试图在打字稿中实现一个类似图的数据结构,并且在尝试了许多解决方案之后,很难对其进行类型保护:
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>();