0
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?

お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

Mapped Types による配列型・タプル型の保持

Last updated at Posted at 2024-07-15

Mapped Types

Mapped Types は{ [P in X]: Y }の形で宣言できる型で、Xで指定したキーを持つオブジェクト型を宣言できます。
Xに指定できる型はプロパティのキーとなれる型string | number | symbolの部分型に限られます。

ちなみにstring | number | symbolには、PropertyKeyという別名がついています。

typescript/lib/lib.es5.d.ts
declare type PropertyKey = string | number | symbol;

配列型・タプル型の構造の保持

型引数Tをもち、{ [P in keyof T]: U }という形の型にTとして配列型やタプル型を渡した場合、配列構造やタプル構造がそのまま保持されます。

これはTypeScript 3.1 から導入された仕組みのようですね。

配列型の構造の保持

type HMT<T> = { [P in keyof T]: string | undefined }という型引数TをとるHMT<T>型について考えてみます。
以下のようにTとして配列を渡した場合と、型引数を介さずに直接Tの部分に配列を記述した場合を比べてみると、得られる型が異なっていることがわかります。

type HMT<T> = {
    [P in keyof T]: string | undefined
}

//type ArrayHMT = (string | undefined)[]
type ArrayHMT = HMT<number[]>

// type ArrayMT = {
//     [x: number]: string | undefined;
//     length: string | undefined;
//     toString: string | undefined;
//     toLocaleString: string | undefined;
//     pop: string | undefined;
//     push: string | undefined;
//     ... 26 more ...;
//     readonly [Symbol.unscopables]: string | undefined;
// }
type ArrayMT = {
    [P in keyof number[]]: string | undefined
}

型引数を介した場合(HMT<number[]>)には、得られる型が配列型(string | undefined)[]となっています。

一方で、直接配列型を記述した場合には、配列ではなくインデックスシグネチャ[x: number]: string | undefined;に変換されており、配列操作用の関数名poppushもプロパティキーに含まれてしまっています。

タプル型の構造の保持

配列と同様のことがタプル型にも適用されます。

type HMT<T> = {
    [P in keyof T]: string | undefined
}

// type TuppleHMT = [string | undefined, string | undefined]
type TuppleHMT = HMT<[number, string]>

// type TupleMT = {
//     [x: number]: string | undefined;
//     0: string | undefined;
//     1: string | undefined;
//     length: string | undefined;
//     toString: string | undefined;
//     toLocaleString: string | undefined;
//     pop: string | undefined;
//     ... 27 more ...;
//     readonly [Symbol.unscopables]: string | undefined;
// }
type TupleMT = {
    [P in keyof [number, string]]: string | undefined
}

[number, string]型を型引数に渡した場合には、タプル構造が保持された状態の方が得られています。
一方、直接タプル型を記述した場合にはタプルの配列操作用の関数に加えて、タプルの要素番号01も含めて型情報に含まれてしまっています。

おわりに

配列型やタプル型をMapped Types によって操作する場面で配列のラッパーオブジェクトのプロパティキーが顔を出してくると使いづらいため、型引数を介した操作の場合には配列やタプルの構造をそのまま保持するようにしてくれているみたいですね。

{ [P in keyof T]: U }という形のMapped Types はHomomorphic Mapped Types という名で呼ばれ、配列型・タプル型の他にも、オブジェクト型を受け取った場合に構造が保持されるような仕組みとなっています。

0
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
0
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?