You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript 泛型函数中如何获取传入的类型约束实现instanceof校验

问题核心原因

TypeScript 的泛型属于编译时类型语法,编译为 JavaScript 后会完全擦除类型信息,运行时不存在你声明的Type泛型变量,因此piece instanceof Type必然无法生效,你必须传入一个运行时可用的实体来完成类型校验。

可行解决方案

方案1:传入类构造函数作为运行时参数

这是改动最小的方案,仅需要修改方法签名新增构造函数入参即可:

// 先定义构造函数类型约束
type PieceConstructor<T extends Bishop | Queen> = new (...args: any[]) => T;

static controlsDiagonal<T extends Bishop | Queen>(
  board: (Piece | null)[][], 
  x: number, 
  Colour: ColourEnum,
  // 新增运行时可用的构造函数参数
  PieceClass: PieceConstructor<T>
): boolean{
    const rankMultipliers = [1, -1, 1, -1];
    const fileMultipliers = [1, -1, -1, 1];
    const coordinates = new Coordinates(x);

    for(let i = 0; i < 4; i++){
      let offset = 1;
      let fromRank = offset * rankMultipliers[i] + coordinates.rank;
      let fromFile = offset * fileMultipliers[i] + coordinates.file;

      while(fromRank < 8 && fromRank > -1 && fromFile < 8 && fromFile > -1) {
        const piece = board[fromRank][fromFile];

        if(piece !== null){
          // 直接用传入的构造函数做instanceof校验
          if(piece instanceof PieceClass && piece?.getColour() === Colour)
            return true;
          break;
          }

        fromRank = ++offset * rankMultipliers[i] + coordinates.rank;
        fromFile = offset * fileMultipliers[i] + coordinates.file;
      }
    }

    return false;
  }

调用方式对应调整为:

return Bishop.controlsDiagonal(board, x, Colour, Bishop);
return Bishop.controlsDiagonal(board, x, Colour, Queen);

如果需要兼容你原来的调用习惯,可以给构造函数参数加默认值:

static controlsDiagonal<T extends Bishop | Queen>(
  board: (Piece | null)[][], 
  x: number, 
  Colour: ColourEnum,
  PieceClass: PieceConstructor<T> = Bishop as unknown as PieceConstructor<T>
): boolean

默认检查Bishop时直接调用Bishop.controlsDiagonal(board, x, Colour)即可,检查Queen时再传第四个参数。


方案2:用Mixin模式解决单继承限制(更合理的复用方案)

针对你提到的TypeScript单继承、需要共享方法给Queen的需求,Mixin是TS原生支持的标准方案,完全不存在过度设计的问题,复用逻辑更合理:

// 定义基础构造函数类型
type PieceConstructor = new (...args: any[]) => Piece;

// 实现对角线检测能力的Mixin
function WithDiagonalControls<T extends PieceConstructor>(Base: T) {
  return class extends Base {
    static controlsDiagonal(
      board: (Piece | null)[][], 
      x: number, 
      Colour: ColourEnum
    ): boolean {
      const rankMultipliers = [1, -1, 1, -1];
      const fileMultipliers = [1, -1, -1, 1];
      const coordinates = new Coordinates(x);

      for(let i = 0; i < 4; i++){
        let offset = 1;
        let fromRank = offset * rankMultipliers[i] + coordinates.rank;
        let fromFile = offset * fileMultipliers[i] + coordinates.file;

        while(fromRank < 8 && fromRank > -1 && fromFile < 8 && fromFile > -1) {
          const piece = board[fromRank][fromFile];
          if(piece !== null){
            // 静态方法的this指向当前调用的类,不需要额外传参
            if(piece instanceof this && piece?.getColour() === Colour)
              return true;
            break;
          }
          fromRank = ++offset * rankMultipliers[i] + coordinates.rank;
          fromFile = offset * fileMultipliers[i] + coordinates.file;
        }
      }
      return false;
    }
  }
}

// Bishop和Queen分别引入Mixin能力
class Bishop extends WithDiagonalControls(Piece) {
  // 原有Bishop逻辑不变
}
// Queen继承Rook的同时获得对角线检测能力
class Queen extends WithDiagonalControls(Rook) {
  // 原有Queen逻辑不变
}

调用方式完全符合直觉:

return Bishop.controlsDiagonal(board, x, Colour);
return Queen.controlsDiagonal(board, x, Colour);

内容的提问来源于stack exchange,提问作者Paweł

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 00:15:05