国际象棋符号:TypeScript 模板文字:TS2590:表达式生成一个联合类型,该类型太复杂而无法表示

问题描述 投票:0回答:1

我正在尝试用 TypeScript Template Literals 表示 代数国际象棋表示法

我使用的类型:

export type ChessPiece = 'P' | 'K' | 'Q' | 'R' | 'B' | 'N';
export type ChessX = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h';
export type ChessY = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;

export type AlgebraicMoveNotationDisambiguate = '' | ChessX | ChessY | `${ChessX}${ChessY}`;
export type AlgebraicMoveNotationBase = `${ChessPiece | ChessX}${AlgebraicMoveNotationDisambiguate}${'x' | ''}${ChessX}${ChessY}`;
export type AlgebraicMoveNotationPromote = `${ChessX}8${ChessPiece}`;
export type AlgebraicMoveNotationDecoration = `${'' | '+' | '#'}`;
export type AlgebraicMoveNotation = 'O-O' | 'O-O-O' | `${AlgebraicMoveNotationBase|AlgebraicMoveNotationPromote}${AlgebraicMoveNotationDecoration}`;

这会在第 6 行产生错误 (

AlgebraicMoveNotationBase
):

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

我知道这是一个相当复杂的表达式,一直计算所有可能的值可能是不可行的(我算了一下,最终类型中有大约 35 亿种组合

AlgebraicMoveNotation
)。

我的问题是 - 有没有一种方法可以将 TS 配置为仅评估分配的值,而不尝试理解所有可能的类型,例如:

// Example 1 =======

const someMove: AlgebraicMoveNotation = 'exd5'; // <- Checks provided literal is valid

// Example 2 =======

const validateMoves(moves: AlgebraicMoveNotation[]): void {
    // ...
}

validateMoves([ // <- Checks provided literals in array are valid
    'Nf6+',
    'a8Q',
    'Qexe1#',
]);

我尝试检查类似的错误,但没有找到任何相关的内容。


更简单的示例,更容易复制:

export type ChessPiece = 'P' | 'K' | 'Q' | 'R' | 'B' | 'N';
export type ChessX = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h';
export type ChessY = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;

export type AlgebraicMoveNotationDisambiguate = '' | ChessX | ChessY | `${ChessX}${ChessY}`;
export type AlgebraicMoveNotationCapture = '' | 'x';
export type AlgebraicMoveNotationBase = `${ChessPiece | ChessX}${AlgebraicMoveNotationDisambiguate}${AlgebraicMoveNotationCapture}${ChessX}${ChessY}`;
typescript types pattern-matching
1个回答
0
投票

感谢@kelsny和@jcalz!

我能够想出这个解决方案:

export type ChessPiecePromotes = 'Q' | 'R' | 'B' | 'N';
export type ChessPieceWithoutPawn = 'K' | ChessPiecePromotes;
export type ChessPiece = 'P' | ChessPieceWithoutPawn;
export type ChessX = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h';
export type ChessY = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;

export type AlgebraicMoveNotationTarget = `${ChessX}${ChessY}`
export type AlgebraicMoveNotationDisambiguate = '' | ChessX | ChessY | AlgebraicMoveNotationTarget;
export type AlgebraicMoveNotationCapture = '' | 'x';
export type AlgebraicMoveNotationPromote = `${ChessX}8${ChessPiecePromotes}`;
export type AlgebraicMoveNotationDecoration = '' | '+' | '#';
export type AlgebraicMoveNotationCastle = 'O-O' | 'O-O-O';

export type CheckAlgebraicMoveNotation<T extends string> =
    |
        T extends `${ChessX}${infer C}` ?
            C extends `${AlgebraicMoveNotationCapture}${infer G}` ?
                G extends `${AlgebraicMoveNotationTarget}${infer E}` ?
                    E extends AlgebraicMoveNotationDecoration ? T
                        : never : never : never : never
    |
        T extends `${ChessPieceWithoutPawn}${infer D}` ?
            D extends `${AlgebraicMoveNotationDisambiguate}${infer C}` ?
                C extends `${AlgebraicMoveNotationCapture}${infer G}` ?
                    G extends `${AlgebraicMoveNotationTarget}${infer E}` ?
                        E extends AlgebraicMoveNotationDecoration ? T
                            : never : never : never : never : never
    | T extends AlgebraicMoveNotationPromote ? T : never
    | T extends AlgebraicMoveNotationCastle ? T : never
;

export function notation<T extends string>(move: T extends CheckAlgebraicMoveNotation<T> ? T : never) {
    return move;
}
© www.soinside.com 2019 - 2024. All rights reserved.