LoginSignup
1
0

More than 1 year has passed since last update.

TypeScriptで「固定長の配列」を再帰を使って宣言する方法

Posted at

はじめに

配列の長さを静的に決めておきたいことがよくあります。例えば9×9のリバーシの盤面を表現したい場合、長さ9のnumber(1マスの中の情報はnumberで表すとして)の配列を、9個用意することになり、そこからはみ出る参照は、実行前に取り除いておきたいものです。

const board: [固定長配列の上手い型定義] = [[0,0,0,0,0,0,0,0,0], ... , [0,0,0,0,0,0,0,0,0]]

console.log(board[4][5]) // <- 0
console.log(board[9][0]) // <- 9×9の範囲を超えているので、コンパイル時にエラーが出るようにしたい

「長さ9のnumberの配列」は、TypeScriptの「タプル」を使えば、次のように表すことができます:

const row: [number, number, number, number, number, number, number, number, number] = [0,0,0,0,0,0,0,0,0]

じゃあリバーシの盤面の型はこう?

type Row = [number, number, number, number, number, number, number, number, number]
type Board = [Row, Row, Row, Row, Row, Row, Row, Row, Row]

…こんな汚ねえコードは書きたくねえ!!!!!ってことで、以下のよう 「固定長な配列」を「再帰」を使って表現してみます:

結論

type FixedLengthArray<T, N extends number, A extends any[] = []> = A extends { length: N } ? A : FixedLengthArray<T, N, [ ...A, T ]>

配列の要素の型引数 T, 配列の長さを表す型引数 N, 配列の蓄積を表す型引数 Aに対して、Conditional Typesを使ってAが長さNに達しているかどうか判定します。既にNに達していた場合はそのままAを返せばよく、達していなかった場合は再帰的にFixedLengthArrayを呼んで配列の蓄積の部分を引き伸ばしていくイメージです。

これを使えば、リバーシの盤面は次のように簡潔に表せますね!

type Row = FixedLengthArray<number, 9>
type Board = FixedLengthArray<Row, 9>

// もしくはRowをかませず単純に
type Board = FixedLengthArray<FixedLengthArray<number, 9>, 9>

TypeScriptで、楽しい型パズルライフを送りましょう!

参考文献

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0