1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[TypeScript] 配列をマスターしよう!

Last updated at Posted at 2024-04-22

はじめに

早くもTypeScript4件目となる記事です...
今回は配列についてまとめてみました。

【目次】

まずは基本的な型宣言をマスターしよう!
オブジェクト型の型宣言をマスターしよう!
関数の型定義をマスターしよう!
配列をマスターしよう! ←🈁
インターフェースをマスターしよう!
クラスを使いこなそう!
型修飾子についての理解を深めよう!
ジェネリックをマスターしよう!
独自の構文拡張をマスターしよう!


TypeScriptにおける配列

TypeScriptにおける配列のベストプラクティスとして、
「1つの配列につき、1つのデータ型」 という思考を尊重しています。

そのため既存の配列と異なる型のデータを挿入しようとすると 型エラー が発生します。

let strs = ["Hello", "World"]

// OK
strs.push("!")

// NG: Argument of type 'number' is not assignable to parameter of type 'string'.
strs.push(1234)

配列の型定義

配列の型定義は以下の形式で行います。
let 変数名: データ型[]

let strs: string[] = [];
let nums: number[] = [];

合併型の配列

「1つの配列につき、1つのデータ型」 というベストプラクティスは理解できましたが、異なるデータ型を1つの配列で扱いたいこともありますよね。

そのようなケースでは、合併型の配列を利用します。
let 変数名: (型A | 型B)[]

// string or number型のデータを格納する配列
let stringAndNumbers: (string | number)[] = [];

// OK
stringAndNumbers.push(1234);
stringAndNumbers.push("1234");

// NG: Argument of type 'boolean' is not assignable to parameter of type 'string | number'.
stringAndNumbers.push(true);

:pencil: any型について

異なるデータ型を格納する配列の定義としてany[]を利用することもできます。
しかし、any型は間違った値の追加を許してしまう可能性があり、TypeScriptの恩恵を十分に受け取れません。

よほどのことがない限り利用しないようにしましょう。

let anyArray: any[] = []

タプル

タプルとは、固定サイズの配列です。
それぞれのインデックスにおいて、決まった型を持ちます。

以下の例において、TypeScritは以下の型定義を推論します。

  • tuple[0]number
  • tuple[1]string

そのため、各データ型の固有メソッドが型の絞り込みなしに実行できます。

let tuple: [number, string]
tuple = [1234, "Hello"]

// OK
tuple[0].toFixed
// OK
tuple[1].toUpperCase

タプルへの値割当

タプル型は可変長引数よりも限定的な型です。
タプル型の変数に対して、可変長引数の割り当てはできません。

変数listはTypeScriptによって(string | number)[]型と型推論されています。
そのため、タプル型の[string, number]に割り当てしようとするとエラーが発生します。

let list = ["str", 1234];

// NG: Type '(string | number)[]' is not assignable to type '[string, number]'
let tuple: [string, number] = list

// OK
let listSecond: [string, number] = ["str", 1234];

スプレッド引数とタプル

TypeScriptはスプレッド変数に対しても、正確な型チェックを行います。

変数args(string | number)[] 型と型推論されています。

関数fnにスプレッド引数として渡されていますが、渡された引数はそれぞれ string | number と推論されるため、型エラーが発生します。

function fn(input: string, num: number) {
    console.log(input, num)
}

let args = ["inputText", 1234]

// NG: A spread argument must either have a tuple type or be passed to a rest parameter.
fn(...args);

これを改善するには、配列をタプル型として定義します。
こうすることで引数1がstring、 引数2がnumber型と推論され、型エラーが解消されます。

function fn(input: string, num: number) {
    console.log(input, num)
}

let args:[string, number] = ["inputText", 1234]

// OK
fn(...args);

タプルの型推論

前述したように、TypeScriptはコード内で生成された配列を可変長引数としてみなします。

上記のようなケースでは、配列がタプル型であることを宣言する必要があります。
配列がタプル型であることを示すためのアプローチを2つご紹介します。

明示的なタプル型として定義

以下の関数fnは戻り値としてタプル型を定義しています。
この変数の戻り値を、TypeScriptは[string, number]のタプルであることを推論します。

よって、outputPair(...returnPair()) は型エラーが発生しません。

function returnPair(): [string, number] {
    return ["CodeTaro", 24]
}

function outputPair(name: string, age: number) {
    console.log(name, age)
}

// OK
outputPair(...returnPair());
constアサーション

値の末尾に as constアサーションを定義することで、値が読み取り専用であることを推論します。

as constアサーションを配列の末尾に付与することで、TypeScript はその配列をタプル型として扱うようになります。

function outputPair(name: string, age: number) {
    console.log(name, age)
}

let pair = ["Taro", 24] as const;
// OK
outputPair(...pair);

:pencil: constアサーションを付与した変数に対して、値の更新を実行すると型エラーが発生しm

let pair = ["Taro", 24] as const;

// NG: Cannot assign to '0' because it is a read-only property.
pair[0] = "Tom"

まとめ

以上です!
思った以上に濃い内容となりました。
型推論は素晴らしい... :sparkles:

次節として、インターフェース に関する記事を公開しておりますので、よろしければご覧ください🙏

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?