我正在使用Typescript创建将棋游戏板。将棋板有9个等级和文件。
我想声明一个9x9多维数组作为一种类型,以确保数组的大小和内容。
目前,我正在以这种方式创建9x9木板类型:
type Board9x9<P> = [
[P, P, P, P, P, P, P, P, P],
[P, P, P, P, P, P, P, P, P],
[P, P, P, P, P, P, P, P, P],
[P, P, P, P, P, P, P, P, P],
[P, P, P, P, P, P, P, P, P],
[P, P, P, P, P, P, P, P, P],
[P, P, P, P, P, P, P, P, P],
[P, P, P, P, P, P, P, P, P],
[P, P, P, P, P, P, P, P, P]
];
interface IShogiBoardInternalState {
board: Board9x9<IShogiPiece>;
playerName: string;
isYourTurn: boolean;
}
问题:是否有一种不太繁琐,更通用的方式来定义我称为Board9x9<P>
的元组类型?
答案 0 :(得分:17)
打字稿3引入了rest elements in tuple types
元组类型的最后一个元素可以是... X形式的rest元素,其中X是数组类型
要限制元组的长度,我们可以使用与{ length: N }
的交集
type Tuple<TItem, TLength extends number> = [TItem, ...TItem[]] & { length: TLength };
type Tuple9<T> = Tuple<T, 9>;
type Board9x9<P> = Tuple9<Tuple9<P>>;
这在初始化Tuple
类型的变量时起作用:
const t: Tuple<number, 1> = [1, 1] // error: 'length' incompatible.
在此警告,如果您尝试访问超出元组范围的索引中的非元素,则打字稿不会警告您:
declare const customTuple: Tuple<number, 1>;
customTuple[10] // no error here unfortunately
declare const builtinTuple: [number];
builtinTuple[10] // error: has no element at index '10'
有一种suggestion添加了一种通用方法来指定元组类型的长度。
答案 1 :(得分:5)
一个快速的简化方法是创建一个Tuple9
类型,该类型可用于创建矩阵的第一级和第二级:
type Tuple9<T> = [T, T, T, T, T, T, T, T, T]
type Board9x9<P> = Tuple9<Tuple9<P>>
答案 2 :(得分:1)
借助元组类型别名,您可以制作任意 NxN 板:
type Tuple<T, N extends number, A extends any[] = []> = A extends { length: N } ? A : Tuple<T, N, [...A, T]>;
因此,在您的情况下,您可以执行以下操作:
type Tuple<T, N extends number, A extends any[] = []> = A extends { length: N } ? A : Tuple<T, N, [...A, T]>;
type Board9x9<P> = Tuple<Tuple<P, 9>, 9>;
答案 3 :(得分:0)
type PushFront<TailT extends any[], FrontT> = (
((front : FrontT, ...rest : TailT) => any) extends ((...tuple : infer TupleT) => any) ?
TupleT :
never
)
type Tuple<ElementT, LengthT extends number, OutputT extends any[] = []> = {
0 : OutputT,
1 : Tuple<ElementT, LengthT, PushFront<OutputT, ElementT>>
}[
OutputT["length"] extends LengthT ?
0 :
1
]
//type t3 = [string, string, string]
type t3 = Tuple<string, 3>
//type length = 0 | 3 | 1 | 2
type length = Partial<Tuple<any, 3>>['length']
Add a generic way to specify length of a tuple type #issuecomment-513116547
答案 4 :(得分:0)
对常见用例的想法(如在这个问题中),其中您尝试创建的类型不应具有会改变底层数组的不安全数组方法(如 push
、pop
、等):
const board: Tuple<string, 4> = ["a", "b", "c", "d"];
board.pop()
const fourthElement: string = board[3]; // No TS error
fourthElement.toUpperCase() // Errors when run, but no TS error
不要使用元组,而是考虑使用仅限于某些索引的索引签名:
// type BoardIndicies = 0 | 3 | 1 | 2
type BoardIndicies = Partial<Tuple<never, 3>>['length']
const board: Record<BoardIndicies, string> = ["a", "b", "c", "d"];
board.pop() // ERROR: Property 'pop' does not exist on type 'Record<0 | 3 | 1 | 2, string>'.