TypeScriptのreduce / mapを「型定義(シグネチャ)」から理解する

社内勉強会でTypeScript勉強を行ったのでメモとして残します。

内容をAIと話しながら内容を整理して、最終的なまとめはAIに行ってもらいました。
あくまで備忘録して残したいため。


以下概要

React + TypeScript の勉強会で印象的だったのが、
reduceやmapの実装ではなく「型定義(シグネチャ)」を見るという話でした。

普段は

array.map(...)
array.reduce(...)

のように使うだけですが、
TypeScriptでは 型定義を見ると理解がかなり深まるという話でした。

実際に画面に型定義を出して、指差しながら説明してもらったのがとてもわかりやすかったので、自分のメモとして整理しておきます。


配列とは何か

まず前提として、TypeScriptでは配列はこう定義されています。

interface Array<T>

ここで

T = 配列の要素の型

です。

例えば

const a = [1,2,3]

これは実際には

Array<number>

つまり

T = number

になります。

勉強会で言われて印象に残ったのは、

「配列です」ではなく「何の配列か」が重要

という話でした。

Javaだと

List<String>

Pythonだと

list[str]

のように 要素型が必ず決まるので、

Array<T>

も同じ考え方です。


new Array()

例えば

const b = new Array<string>()

これは

Array<string>

を作っているという意味です。

つまり

T = string

なので、この配列には

string

が入る想定になります。


実際のreduceの型定義

TypeScriptのArrayにはこういう型定義があります。

interface Array<T> {
  reduce<U>(
    callbackfn: (
      previousValue: U,
      currentValue: T,
      currentIndex: number,
      array: T[]
    ) => U,
    initialValue: U
  ): U;
}

ここで重要なのが

T
U

です。


T と U とは

T = 配列の要素型
U = reduceの結果の型

です。


実際のコードで考える

const a = [1,2,3]

これは

Array<number>

なので

T = number

です。


reduceの例

const b = new Array<string>()

b.reduce((acc, hoge, foo, piyo) => {
  return ''
}, 'a')

ここで

T = string

になります。

なので

hoge: string

です。


initialValueでUが決まる

この部分

'a'

initialValue

なので

U = string

になります。

つまり

acc: string
return: string

になります。


勉強会での説明(ここが理解ポイント)

勉強会では型定義を見ながらこう説明してくれました。

reduce<U>(
  callbackfn: (
    previousValue: U,
    currentValue: T,

ここで

T
U

が決まると

他の場所も全部決まる

という説明でした。

例えば

T = string

なら

currentValue: string
array: string[]

になります。


mapの型定義

参考としてmapも見てみます。

map<U>(
  callbackfn: (value: T, index: number, array: readonly T[]) => U
): U[];

ここでは

T → U

という変換です。

例えば

[1,2,3].map(n => n.toString())

ここでは

T = number
U = string

なので

string[]

が返ります。


reduceとmapの違い

整理すると

map

T → U

reduce

T → U (集約)

mapは

number[] → string[]

reduceは

number[] → number

などになります。


コードフォーマットの話

勉強会では、reduceの改行位置についても話がありました。

array.reduce(
  (acc, cur) => {
    return something
  },
  initialValue
)

または

array.reduce((acc, cur) => {
  return something
}, initialValue)

まとめ

今回の勉強会で一番学びになったのは

実装ではなく型定義を見る

ということでした。

特に

interface Array<T>
reduce<U>()
map<U>()

のようなジェネリクスを見ると

  • T = 配列の要素型
  • U = 変換後の型 / 結果型

が理解できます。

reduceやmapは普段何気なく使っていますが、
型定義を読むことで TypeScriptの理解がかなり深まると感じました。

コメント

タイトルとURLをコピーしました