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

More than 5 years have passed since last update.

初心者殺しなTypeScriptのジェネリクス(<>←これ)攻略

Posted at

はじめに

社内向けの教育資料を転載。
以下本文。

ジェネリクスの特徴

  1. 三角カッコの不思議なやつ
  2. ライブラリとか覗くとよく生息してる
  3. エラーのトレースバックでもよくいる
  4. 初心者殺し!!!

ジェネリクスを一言で

型が違うが動作がほぼ同じ関数・オブジェクトを型の違いを気にせず定義する機能。

むずかしい...

具体例

いろんな型のデータに対して+操作する関数を考える。

const addInt = (a: number, b: number) => a + b
addInt(1, 2) // 3

const addStr = (a: string, b: string) => a + b
addStr("a", "b") // "ab"

const addArr = (a: any[], b: any[]) => a + b
addArr([1, 2, 3], [4, 5]) // [1, 2, 3, 4, 5]

なんか型が違うだけでほとんど同じ操作してる気がする...
3回もほぼ同じこと書いてるし...
めんどくさい...

と昔の偉いエンジニアは考えた。
めんどくさいときは共通化してサボるのが鉄則。
では共通点とは?相違点は?

共通点

2つのデータに対して+操作を行う

相違点

入ってくる2つのデータの型が違う。

すなわち、abという両方型が同じで何らかの型を持つ、その型を仮にTと呼ぼう、が入ってくると戻り値の方もTになる。

共通点をくくりだしてまとめる

共通化するとき各ケースで異なるものはどう取り扱うだろう。
例えば何回も使用する共通の処理をまとめたものである関数では、入力値が毎回異なるので"引数"という概念で相違点に柔軟に対応する。

実はジェネリクスはこの引数みたいなもの。
違うのは普通の引数がデータに対しての変数であるのに対し、ジェネリクスは型に対しての引数であるということ。

実際に上の3つの関数をジェネリクスを用いて再定義してみよう。

const add<T>(a: T, b: T) => a + b

add<number>(1, 2) // 3, number型を受け取ってnumberを返す
add<string>("a", "b") // "ab", string型を受け取ってstringを返す
add<any[]>([1, 2, 3], [4, 5]) // [1, 2, 3, 4, 5], any[]型を受け取ってany[]を返す

こうやって<T>を型引数として宣言し、使用時に型を代入する。
上で説明したように、addはまさにT型の変数abを受け取ってT型の戻り値を返す関数に様変わりした。
こうして鬱陶しいaddの定義は一回ですみ、共通化の安寧がもたらされた。

まとめ

ジェネリクスはライブラリ使用時など必ず出てくる概念。
ある程度は知らずにコードを書けるが、ある時点で必ず成長がとまる。
だから早めに習得して、みんなもTypeScriptで気持ちよくなろう!

挑戦問題

実は上でジェネリクスを用いて共通化したadd関数はエラーを起こす。
何故かわかるかな?

5
0
1

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