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ł
相关产品推荐
相关产品推荐

