打字稿:我可以定义一个n长度的元组类型吗?

Luc*_*gan 13 typescript

我正在使用Typescript创建一个shogi游戏板.将棋盘有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;
}
Run Code Online (Sandbox Code Playgroud)

问题:是否有一种不那么繁琐,更通用的方法来定义我称之为的元组类型Board9x9<P>

Ale*_* L. 26

Typescript 3 在元组类型中引入了rest元素

元组类型的最后一个元素可以是... 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>>;
Run Code Online (Sandbox Code Playgroud)

  • @trias你是对的,这与问题无关,但这会触发联合的分配并允许诸如:`type VarLength = Tuple&lt;number, 0 | 2 | 4&gt;;` 结果是 `[] | [数量,数量] | [数字,数字,数字,数字]` (3认同)
  • 为什么在你的例子中“N extends N”?这不总是正确的吗? (2认同)

Tit*_*mir 12

一个快速的简化方法是创建一个Tuple9类型,该类型可用于创建矩阵的第一层和第二层:

type Tuple9<T> = [T, T, T, T, T, T, T, T, T]
type Board9x9<P> = Tuple9<Tuple9<P>>
Run Code Online (Sandbox Code Playgroud)

  • 那真是太光鲜了,但是如果我想为Taikyoku shogi板创建`Tuple36 &lt;T&gt;`的话,那仍然会变得很丑陋。xD 不过,与我的策略相比,您的策略在代码缩减方面是巨大的。谢谢! (2认同)
  • 的确,这种方法比Aleksey的方法更冗长。但是,当我使用Aleksey的方法时,TS编译器允许我访问超出范围的索引,而此答案中的方法阻止了它。例如,如果我声明`const q:Board9x9 &lt;number&gt; = ...`,则使用Aleksey的方法`q [100] [100]`可以正常编译,但是使用此答案中的代码,编译器*正确报告*索引问题。 (2认同)

sst*_*tur 6

您可以借助 Tuple 类型别名制作任意 NxN 板:

type Tuple<T, N extends number, A extends any[] = []> = A extends { length: N } ? A : Tuple<T, N, [...A, T]>;
Run Code Online (Sandbox Code Playgroud)

所以在你的情况下你会做类似的事情:

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>;
Run Code Online (Sandbox Code Playgroud)