强制依赖于构造函数参数的泛型类型

当 Iterable 传递给构造函数时,是否可以强制执行 T = Tile?

class Grid<T extends Tile> {
  tiles = new Map<T>();
  setTile(tile: T) {
    this.tiles.set(tile.toString(), tile);
  }
  constructor();
  constructor(coords: Iterable<Coords>);  // enforce T = Tile in this case
  constructor(tiles: Iterable<T>);
  constructor(input?: Iterable<T> | Iterable<Coords>) {
    if (!input) return;
    for (const t of input) {
      if (t instanceof Tile) {
        this.setTile(t);
      } else {
        this.setTile(new Tile(coord));  // ts(2345) error here
      }
    }
  }
}
回答
D
Dr. Osborne Von
3周前

您可以允许按如下方式传递 Tile 构造函数:

class Tile {
  constructor(coord: Coords) { }
}
type Coords = { x: number }

class Tile2 extends Tile { y = 1 }

class Grid<T extends Tile = Tile> {
  tiles = new Map<string, T>();
  setTile(tile: T) {
    this.tiles.set(tile.toString(), tile);
  }
  constructor();
  // if TileConstructor is provided, use it
  constructor(coords: Iterable<Coords>, TileConstructor: new (c: Coords) => T);
   // Tile fallback, disallow on non-just-Tile types
  constructor(coords: Iterable<Coords> & (Tile extends T ? unknown : never));
  constructor(tiles: Iterable<T>);
  constructor(
    input?: Iterable<T> | Iterable<Coords>,
    TileConstructor: new (c: Coords) => T = Tile as new (c: Coords) => T
  ) {
    if (!input) return;
    for (const t of input) {
      if (t instanceof Tile) {
        this.setTile(t);
      } else {
        this.setTile(new TileConstructor(t));
      }
    }
  }
}
new Grid([{ x: 1 }]) // ok
new Grid<Tile2>([{ x: 1 }]) // error
new Grid([{x: 1}, Tile2]) // ok