Typescriptタプルの詳細
簡単に思い出してください。最も基本的な定義のタプルは、複数の部分で構成される単なるデータ構造です。 Typescriptなどのプログラミング言語でタプルを使用する範囲では、データが最も一般的に順序付けられていることに注意することも重要です。
簡単な例は、Typescriptでタプルがどのように定義されているかを示しています。
// This tuple is defined as a set
// of two numbers.
const scores: [number, number] = [1, 2];
// For comparison, this tuple consists
// of three elements, each of a different
// type. Not that the ordered nature of
// tuples in TS becomes very clear here.
const result: [string, number, boolean] = ["id", 101, false];
// And as a "nice-to-know", you can even
// provide lables for the tuple elements.
// This doesn't have any effect on the typesystem
// itself and only (may) improve documentation.
const output: [id: number, name: string] = [101, "Tom"];
オプションの要素を持つタプル
Typescriptが時間の経過とともに改善されるにつれて、タプルの実装も改善されました。必須である必要がある要素を定義する必要があるだけではありません。オプションとして要素を入力することもできるようになりました。わからない場合、Typescriptは疑問符を一般的な記号として使用して、要素をオプションとして定義します。つまり、実行時に使用できるようになりますが、そうする必要はありません。
別の例は、私がそれが何を意味するかを示しています。
// Similar to our previous example, but in this
// case the the tuple's last element doesn't have
// to be provided (or can be undefined at runtime).
type Tuple = [id: number, name?: string];
const a: Tuple = [101];
const b: Tuple = [42, "Tom"];
Typescriptタプルの残りの要素
残りの要素を使用すると、特定のタイプのタプル内の後続のすべての要素をマークする非常に強力なタイプが手元にあります。したがって、2つの要素を持つタプルがあり、2番目の要素がREST要素として定義されている場合、実行時にこのタプル変数に2 + n個の要素を提供できます。
定義を絞り込むために、最近まで、そのような要素はタプルの終わりでのみ許可されていました。これは、restタイプの実行時に任意の数の要素を提供できるため、理にかなっていますが、rest要素ともう1つの他の型付きアイテムを区別するのは非常に複雑になります。
// This example might be a tuple type
// for a CLI similar to Node.js. The first
// two elements are system-internal.
//
// Starting from the 3rd element, a user can
// provide as much arguments as desired, yet
// we can still cleanly handle it with TS. Nice!
let input: [number, boolean, ...string[]];
// Just to show that we really can provide any
// number of rest elements, including 0.
e = [0, false, "max-cache", "1024", "debug", "false"];
e = [0, false];
e = [0, false, "verbose"];
タプルタイプのリーディングまたはミドルレスト要素
タプルの残りの要素を進化させると、Typescript 4.2がリリースされて以来、さらに洗練された実装を作成できます。そして、ここでお詫びする必要があります。ほんの数文前に、最後の要素としてのみREST要素を使用することが必須である方法を書きました。 Typescript 4.2以降、この制限は実際には当てはまりません。タプルのほぼどこにでもレスト要素を配置できるようになったためです。
しかし、いくつかの制限があるだけで、Typescriptは高度なタプルに非常に優れた構文を提供するようになりました。残りの要素は、次の2つのルールに準拠している限り、タプル内のどこにでも発生できます。
- オプションの要素が後に続くことはありません
- 最初の要素の後に他のREST要素はありません
あまりにも多くの理論を話す前に、例を見てみましょう。
// And here comes the fancy part: rest elements
// *not only* at the end of a tuple.
//
// Note: this example is taken directly from the
// TS documentation. For more details, check out the
// links in the addendum.
let foo: [...string[], number];
foo = [123];
foo = ["hello", 123];
foo = ["hello!", "hello!", "hello!", 123];
let bar: [boolean, ...string[], boolean];
bar = [true, false];
bar = [true, "some text", false];
bar = [true, "some", "separated", "text", false];
// And here's an example that shows how the
// type system would catch your errors:
interface Clown { /*...*/ }
interface Joker { /*...*/ }
let StealersWheel: [...Clown[], "me", ...Joker[]];
// ~~~~~~~~~~ Error!
// A rest element cannot follow another rest element.
let StringsAndMaybeBoolean: [...string[], boolean?];
// ~~~~~~~~ Error!
// An optional element cannot follow a rest element.
この記事の残りの要素
Typescriptのタプルに関するこのコンパクトなガイドを締めくくり、基本的な実装を見てから、いくつかのより高度な例を見て、Typescriptがタプルに関して非常に柔軟な型システムを実現する方法を確認しました。この記事を楽しんでいただけたでしょうか。詳しく知りたい場合は、以下の他の投稿の提案をご覧ください。