#TypeScript タプル型

導入

タプルは TypeScript 独自のデータ型であり、JavaScript ではこの型を個別に区別しません。これは、メンバーの型を自由に設定できる配列を表します。つまり、配列の各メンバーの型は異なっていても構いません。

メンバーは異なる型である可能性があるため、タプルは各メンバーの型を明示的に宣言する必要があります。

const s:[文字列、文字列、ブール値]
  = ['a', 'b', true];

上記の例では、タプル s の最初の 2 つのメンバーの型は string、最後のメンバーの型は boolean です。

タプル型の書き方と前章の配列には大きな違いがあります。配列のメンバー型は角括弧の外側 (number[]) に記述され、タプルのメンバー型は角括弧 ([number]) の内側に記述されます。 TypeScript の見分け方は、メンバーの型が角括弧内に記述されている場合はタプル、メンバーの型が括弧の外に記述されている場合は配列です。

// 配列
a:number[] = [1]; とします。

// タプル
t:[数値] = [1] とします。

上記の例では、変数atの値は両方とも[1]ですが、型が異なります。 'a' は配列で、メンバーの型 'number' は角括弧の外側に記述され、't' はタプルで、メンバーの型 'number' は角括弧の内側に記述されます。

タプルを使用する場合、型宣言 (上記の例では [number]) を明示的に指定する必要があり、省略することはできません。そうでない場合、TypeScript は値を配列として自動的に推論します。

// a の型は (number | boolean)[] として推論されます。
a = [1, true] とします。

上の例では、変数 a の値は実際にはタプルですが、TypeScript はそれを共用体型の配列として推論します。つまり、a の型は (number | boolean)[] です。したがって、タプルは明示的に型指定する必要があります。

タプル メンバーの型には疑問符サフィックス (?) を追加して、メンバーがオプションであることを示すことができます。

a:[数値, 数値?] = [1]; とします。

上記の例では、タプル「a」の 2 番目のメンバーはオプションであり、省略できます。

疑問符はタプルの末尾メンバーにのみ使用できることに注意してください。つまり、すべてのオプションのメンバーは必須メンバーの後に来る必要があります。

type myTuple = [
  番号、
  番号、
  番号?、
  弦?
];

上の例では、タプル「myTuple」の最後の 2 つのメンバーはオプションです。つまり、2 人、3 人、または 4 人のメンバーが存在する可能性があります。

各メンバーの型を宣言する必要があるため、ほとんどの場合、タプルのメンバーの数は制限されており、そのメンバーが境界を超えると、タプルに含まれるメンバーの数が明確にわかります。報告されます。

let x:[文字列, 文字列] = ['a', 'b'];

x[2] = 'c' // エラー;

上の例では、変数 x は 2 つのメンバーのみを持つタプルであり、3 番目のメンバーに値が割り当てられると、エラーが報告されます。

ただし、スプレッド演算子 (...) を使用すると、無制限の数のメンバーを持つタプルを表すことができます。

タイプ NamedNums = [
  弦、
  ...番号[]
];

const a:NamedNums = ['A', 1, 2];
const b:NamedNums = ['B', 1, 2, 3];

上記の例では、タプル型 NamedNums の最初のメンバーは文字列であり、後続のメンバーはスプレッド演算子を使用して配列を展開するため、メンバーの数は無限になります。

スプレッド演算子 (...) はタプル内のどこでも使用でき、その後に配列またはタプルのみを続けることができます。

type t1 = [文字列、数値、...ブール値[]];
type t2 = [文字列, ...ブール[], 数値];
type t3 = [...boolean[], 文字列, 数値];

上の例では、スプレッド演算子はそれぞれタプルの末尾、中間、先頭にあり、... の後に配列 boolean[] が続きます。

タプルのメンバーの種類と数がわからない場合は、次のように記述できます。

type タプル = [...any[]];

上の例では、タプル Tuple は任意の数およびタイプのメンバーを保持できます。しかし、このように書くと、タプルと TypeScript を使用する意味が失われます。

メンバー名はタプルのメンバーに追加できます。このメンバー名は説明的なものであり、実際的な効果はありません。

タイプ 色 = [
  赤: 数字、
  緑: 数字、
  青:数字
];

const c:Color = [255, 255, 255];

上の例では、型 Color は 3 つのメンバーを持つタプルです。各メンバーには名前があり、特定の型の前にコロンで区切って書かれます。これらの名前は気軽に付けることができ、各メンバーの意味を説明するためにのみ使用されます。

タプルは角括弧を通してメンバー型を読み取ることができます。

type タプル = [文字列, 数値];
type Age = Tuple[1] // 数値;

上の例では、Tuple[1] は位置 1 のメンバー型を返します。

タプルのメンバーはすべて数値インデックス、つまりインデックスの型はすべて「number」であるため、次のように読み取ることができます。

type タプル = [文字列, 数値, 日付];
type TupleEl = タプル[数値] // 文字列|数値|日付;

上記の例では、Tuple[number] はタプル Tuple のすべての数値インデックスのメンバー型を表すため、string|number|Date が返されます。つまり、この型は 3 つの値の共用体型です。

読み取り専用タプル

タプルは読み取り専用にすることもでき、変更は許可されません。書き込み方法は 2 つあります。

// 書き方その1
type t = readonly [数値, 文字列]

//書き方2
type t = Readonly<[数値, 文字列]>

上記の例では、どちらの書き込みメソッドも読み取り専用タプルを取得できます。2 番目の書き込みメソッドはジェネリック型であり、ツール タイプ Readonly<T> を使用します。

配列と同様、読み取り専用タプルはタプルの親タイプです。したがって、タプルは読み取り専用タプルを置き換えることはできますが、読み取り専用タプルはタプルを置き換えることはできません。

type t1 = readonly [数値, 数値];
type t2 = [数値, 数値];

x:t2 = [1, 2] とします。
y:t1 = x にします。 // 修正します。

x = y // エラー

上記の例では、タイプ t1 は読み取り専用タプル、タイプ t2 は通常のタプルです。 t2 タイプを t1 タイプに割り当てることはできますが、一方でエラーが報告されます。

読み取り専用タプルはタプルを置き換えることができないため、混乱を招くエラーが発生する可能性があります。

関数 distanceFromOrigin([x, y]:[数値, 数値]) {
  戻り Math.sqrt(x**2 + y**2);
}

point = [3, 4] を const としてみましょう。

原点からの距離(ポイント); // エラー

上記の例では、関数 distanceFromOrigin() のパラメータはタプルであり、読み取り専用タプルが渡されるとエラーが報告されます。これは、読み取り専用タプルはタプルを置き換えることができないためです。

読者は、上記の例の [3, 4] as const の書き込み方法が、読み取り専用の配列を生成することを前述したことに気づいたかもしれません。実際には、読み取り専用のタプルも生成されます。生成されるものは実際には読み取り専用の「値型」readonly [3, 4] であるため、読み取り専用の配列または読み取り専用のタプルとして解釈できます。

上記の例で報告されたエラーの解決策は、型アサーションを使用し、最後の行で受信パラメータを通常のタプルとしてアサートすることです。詳細については、「型アサーション」の章を参照してください。

原点からの距離(
  [数値、数値] としてのポイント
)

メンバー数の推定

オプションのメンバーとスプレッド演算子がなければ、TypeScript はタプルのメンバーの数 (つまり、タプルの長さ) を推測します。

関数 f(ポイント: [数値, 数値]) {
  if (point.length === 3) { // エラーレポート
    // ...
  }
}

上記の例では、タプル point の長さが 2 であることが検出されたため、エラーが報告されます。この判断は無意味です。

オプションのメンバーが含まれている場合、TypeScript は可能なメンバーの数を推測します。

関数 f(
  ポイント:[数字、数字?、数字?]
) {
  if (point.length === 4) { // エラーレポート
    // ...
  }
}

上記の例では、TypeScript が point.length の型が 1|2|3 であり、4 に等しくないことが検出されたため、エラーが報告されます。

スプレッド演算子が使用されている場合、TypeScript はメンバーの数を推測できません。

const myTuple:[...string[]]
  = ['a', 'b', 'c'];

if (myTuple.length === 4) { // 正しい
  // ...
}

上記の例では、myTuple には 3 つのメンバーしかありませんが、TypeScript はスプレッド演算子を使用しており、配列のメンバーの数は未定義であるため、そのメンバーの数を推測できません。

スプレッド演算子によってタプルのメンバー数を推測できなくなると、TypeScript は内部的にタプルを配列として扱います。

拡張演算子とメンバーの数

スプレッド演算子 (...) は、配列 (タプルではないことに注意してください) をカンマ区切りのシーケンスに変換します。このとき、メンバーの数が定義されていないため、TypeScript はこのシーケンスのメンバーの数が未定義であるとみなします。配列のは未定義です。

このため、関数呼び出し時にスプレッド演算子を使用して関数パラメーターを渡すと、パラメーターの数が配列の長さと一致しないというエラーが発生する可能性があります。

const arr = [1, 2];

関数 add(x:数値, y:数値){
  // ...
}

add(...arr) // エラーを報告する

関数 add() は 2 つのパラメータしか受け入れられないため、上記の例ではエラーが報告されますが、...arr で渡されると、TypeScript は変換されたパラメータの数が不確実であると判断します。

一部の関数は任意の数のパラメーターを受け入れることができ、その場合、スプレッド演算子はエラーを報告しません。

const arr = [1, 2, 3];
console.log(...arr) // 正しい

上の例では、console.log() は任意の数のパラメータを受け入れることができるため、...arr を渡してもエラーは報告されません。

この問題を解決する 1 つの方法は、メンバー数が不確かな配列を、メンバー数が一定のタプルに書き込み、スプレッド演算子を使用することです。

const arr:[数値, 数値] = [1, 2];

関数 add(x:数値, y:数値){
  // ...
}

add(...arr) // 正しい

上の例では、arr は 2 つのメンバーを持つタプルであるため、TypeScript は、...arr が関数 add() のパラメーターの数と一致できると判断でき、エラーは報告されません。

別の記述方法は、「as const」アサーションを使用することです。

const arr = [1, 2] as const;

TypeScript は、arr の型が readonly [1, 2] であり、配列またはタプルとして使用できる読み取り専用の値の型であると考えるため、上記の書き方も可能です。


作者: wangdoc

アドレス: https://wangdoc.com/

ライセンス: クリエイティブ・コモンズ 3.0