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

用TypeScript模板字面量实现国际象棋代数记法遇TS2590错误求解

解决TypeScript模板字面量生成过大连集类型导致的TS2590错误

我尝试用TypeScript模板字面量表示国际象棋代数记法,定义相关类型后,在AlgebraicMoveNotationBase处遇到以下错误:

TS2590: Expression produces a union type that is too complex to represent.

经计算,AlgebraicMoveNotation类型的组合数高达约35亿种,直接生成所有可能类型完全不可行。需求是让TypeScript仅验证赋值的字面量是否合法,而非预解析生成所有可能的类型。

简化复现代码

// 定义棋盘行列
type File = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h';
type Rank = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8';
type Square = `${File}${Rank}`;

// 棋子类型
type Piece = 'K' | 'Q' | 'R' | 'B' | 'N' | '';

// 吃子标记
type Capture = 'x' | '';

// 将军/将死标记
type Check = '+' | '#' | '';

// 原始实现:生成所有可能的联合类型,导致错误
type AlgebraicMoveNotationBase = `${Piece}${File | Rank | ''}${Capture}${Square}${Check}`;
type AlgebraicMoveNotation = AlgebraicMoveNotationBase | 'O-O' | 'O-O-O'; // 王翼/后翼易位

// 赋值时触发错误
const move: AlgebraicMoveNotation = 'e4';

解决方案:字面量合法性验证而非生成全量类型

通过递归条件类型验证输入的字面量是否符合规则,避免生成庞大的联合类型。核心思路是用类型检查逻辑替代枚举所有可能的组合:

// 基础类型定义不变
type File = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h';
type Rank = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8';
type Square = `${File}${Rank}`;
type Piece = 'K' | 'Q' | 'R' | 'B' | 'N';
type Capture = 'x';
type Check = '+' | '#';

// 验证易位记法
type IsCastling<T extends string> = T extends 'O-O' | 'O-O-O' ? true : false;

// 验证常规走法记法的结构
type IsRegularMove<T extends string> = 
  T extends `${infer P extends Piece | ''}${infer D extends File | Rank | ''}${infer C extends Capture | ''}${infer S extends Square}${infer Ch extends Check | ''}`
    ? (D extends '' ? true : (P extends '' ? false : true)) // 无棋子标记时不能加行列区分符
    : false;

// 总验证类型
type IsAlgebraicMove<T extends string> = IsCastling<T> extends true ? true : IsRegularMove<T> extends true ? true : false;

// 使用类型断言+验证类型来确保字面量合法
type AlgebraicMoveNotation<T extends string> = IsAlgebraicMove<T> extends true ? T : never;

// 合法赋值示例(无错误)
const validMove1: AlgebraicMoveNotation<'e4'> = 'e4';
const validMove2: AlgebraicMoveNotation<'Nf3'> = 'Nf3';
const validMove3: AlgebraicMoveNotation<'Qxd7#'> = 'Qxd7#';
const validMove4: AlgebraicMoveNotation<'O-O'> = 'O-O';

// 非法赋值示例(触发TypeScript错误)
const invalidMove1: AlgebraicMoveNotation<'e9'> = 'e9'; // 行号非法
const invalidMove2: AlgebraicMoveNotation<'x e4'> = 'x e4'; // 格式错误
const invalidMove3: AlgebraicMoveNotation<'Ne'> = 'Ne'; // 缺少目标格子

关键说明

  • 不再生成所有可能的联合类型,而是通过条件类型对输入的字面量进行结构和合法性检查
  • 利用infer关键字拆解模板字面量的各个部分,逐一验证规则
  • 通过AlgebraicMoveNotation<T>的泛型约束,仅在赋值时检查字面量是否符合格式,避免预计算所有组合

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 06:55:33