通用图形数据结构类的打字稿类型安全

问题描述

我试图在打字稿中实现一个类似图的数据结构,并且在尝试了许多解决方案之后,很难对其进行类型保护:

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>();