---
title: TypeScript 勉強会 Day2
tags:  #typescript #lifull  
author: [株式会社LIFULL](https://convert.docswell.com/user/LIFULL)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/9J2GRPNDJR.jpg?width=480
description: 社内で行ったTypeScript勉強会のDay2です。Day2 ではジェネリクスをメインに取り扱います。
published: September 05, 23
canonical: https://convert.docswell.com/s/LIFULL/ZW1R6J-2023-09-05-131308
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/9J2GRPNDJR.jpg)

TypeScript ハンズオン
Day2
Araki Yuki
1
© LIFULL Co.,Ltd. 本書の無断転載、複製を固く禁じます。


# Page. 2

![Page Image](https://bcdn.docswell.com/page/DEYVD5PMEM.jpg)

Genericsとは
Generics


# Page. 3

![Page Image](https://bcdn.docswell.com/page/VJNM6N5378.jpg)

Genericsとは
function test&lt;T&gt;(x: T): T {
return x;
}
const y = test&lt;string&gt;(&#039;aaa&#039;);


# Page. 4

![Page Image](https://bcdn.docswell.com/page/YE9NLRYPE3.jpg)

Genericsとは
型の安全性とコードの共通化を両立するもの


# Page. 5

![Page Image](https://bcdn.docswell.com/page/GE8KXW6X7D.jpg)

Genericsとは
例えば？


# Page. 6

![Page Image](https://bcdn.docswell.com/page/LELZ8N9NJR.jpg)

Genericsとは
配列の最初の要素を返す関数
何も考えずに共通化したコード
function getFirstElement(array: number[]):number {
return array[0];
function getFirstElement(array: any[]):any {
}
return array[0];
function getFirstElement(array: string[]):string{
return array[0];
}
}


# Page. 7

![Page Image](https://bcdn.docswell.com/page/4JMV6XZQJW.jpg)

Genericsとは
これだと型安全に使えない


# Page. 8

![Page Image](https://bcdn.docswell.com/page/PJR2PN6KE9.jpg)

Generics 型変数
型変数


# Page. 9

![Page Image](https://bcdn.docswell.com/page/PEXD3NM57X.jpg)

Generics 型変数
function printAndReturn&lt;T&gt;(value: T): T {
console.log(value);
return value;
Q.型変数のTって何？
A.慣習的に型変数にはT,U,Pが使われます。
Tでないとダメというわけではないです。
}
● Tが型変数と呼ばれる部分
○ 何かしらの型が代入されると思ってください
○ 3つのTは全て同一のものです
● &lt;T&gt;が型変数を定義している部分
● valueの型に使われているTと戻り値に書かれているTは定義された型変数を利用している部分


# Page. 10

![Page Image](https://bcdn.docswell.com/page/3EKXYNGR7D.jpg)

Generics 型引数
型引数


# Page. 11

![Page Image](https://bcdn.docswell.com/page/L7359VNGE5.jpg)

Generics 型引数
function printAndReturn(value: number): number {
console.log(value);
function printAndReturn&lt;T&gt;(value: T): T {
return value;
console.log(value);
return value;
}
}
function printAndReturn(value: string): string {
const value1 = printAndReturn&lt;number&gt;(123);
console.log(value);
const value2 = printAndReturn&lt;string&gt;(&#039;a&#039;);
return value;
}
● &lt;number&gt;が型引数 &lt;T&gt;にnumberを代入しているイメージ
● printAndReturnにnumberの型引数を渡しているので
○ (value: T)のTがnumberになり
○ `: T`の戻り値の型もnumberになる


# Page. 12

![Page Image](https://bcdn.docswell.com/page/87DDG8WN7G.jpg)

Generics 型引数
function printAndReturn&lt;T&gt;(value: T): T {
console.log(value);
return value;
型引数は型の推論が行われます。
変数の123からTがnumberであることが
推測できるので、省略することが可能で
}
す。
const value = printAndReturn(123);
printAndReturn&lt;number&gt;(123);
123から推論できるので&lt;number&gt;の省略が可能
printAndReturn(123);


# Page. 13

![Page Image](https://bcdn.docswell.com/page/VJPX389N78.jpg)

Generics Q1
配列の最初の要素を返す関数をGenericsを使って実装してみる
問題


# Page. 14

![Page Image](https://bcdn.docswell.com/page/2EVL4NMYJQ.jpg)

Generics A1
Genericsを使って共通化したコード
function test&lt;T&gt;(array: T[]):T {
return array[0];
使い方
const array1:string[] = [&#039;a&#039;, &#039;b&#039;];
const array2:number[] = [1,2,3];
}
const a = test(array1);
test&lt;T&gt;
Tは型変数の引数
array: T[]
受け取った型変数の
型の配列を受け取り
:T
受け取った型変数の
型を返す関数
const b = test(array2);


# Page. 15

![Page Image](https://bcdn.docswell.com/page/57GX1KGWEL.jpg)

Generics Q2
配列と判定用の関数を受け取ってFilterする関数の型を定義する
問題


# Page. 16

![Page Image](https://bcdn.docswell.com/page/4EQ8DNXQJP.jpg)

Generics A2
Genericsを使って共通化したコード
function myFilter&lt;T&gt;(arr: T[], predicate: (elm: T) =&gt; boolean): T[] {
const result = [];
for (const elm of arr) {
if (predicate(elm)) {
result.push(elm);
}
}
return result;
}
myFilter&lt;T&gt;
このTは型変数の定義箇所
array: T[]
Tの配列を受け取り
(elm:T) =&gt; boolean
Tをbooleanで判定する関数を受け取る型
: T[]
フィルタリングされたTの配列を返す


# Page. 17

![Page Image](https://bcdn.docswell.com/page/KJ42ZG6YE1.jpg)

Generics Q3
objectに対してIDを付与する関数giveIdの型を定義する
問題


# Page. 18

![Page Image](https://bcdn.docswell.com/page/LE1MRDVN7G.jpg)

Generics A3
Genericsを使って共通化したコード
function giveId&lt;T&gt;(obj:T):T &amp; {id:string}{
const id = &quot;本当はランダムがいいけどここではただの文字列&quot;;
return {
...obj,
id
};
}
giveId&lt;T&gt;
このTは型変数の定義箇所
obj:T
任意のObjectTを受け取り
T &amp; {id:string}
Tと{id:string}のインターセクション型を返す


# Page. 19

![Page Image](https://bcdn.docswell.com/page/GEW31Y3ME2.jpg)

Generics 型変数(複数)
function printAndReturn&lt;T, U&gt;(value1: T,
● 型引数は複数設定することが可能。
value2: U):(T | U)[] {
● &lt;&gt;に対してカンマ区切りで渡す。
console.log(value1);
console.log(value2);
return [value1, value2];
}
const value = printAndReturn&lt;number,
string&gt;(123, &#039;aaa&#039;);


# Page. 20

![Page Image](https://bcdn.docswell.com/page/47ZVPXVME3.jpg)

Generics 型の制約
型の制約


# Page. 21

![Page Image](https://bcdn.docswell.com/page/YJ65M4557V.jpg)

Generics 型の制約
interface Animal {
readonly name: string;
型変数であるTが何者かが不明なので
animal.nameの様に呼び出すことができない
bark(): void;
}
function test&lt;T&gt;(
animal: T
) {
console.log(animal.name);
// ↑compile error
animal.bark();
// ↑compile error
}
ただし &lt;T extends hoge&gt; のようにextendsを使っ
て制約をかけることで、呼び出しが可能になる。


# Page. 22

![Page Image](https://bcdn.docswell.com/page/GJ5YZQYGJ4.jpg)

Generics 型の制約
interface Animal {
readonly name: string;
bark(): void;
}
TがAnimalと互換性のある型という保証があるの
で、animal.nameやanimal.bark();
の呼び出しが可能になる。
function test&lt;T extends Animal&gt;(
animal: T
また下記のような呼び出しは不可能になる
) {
console.log(animal.name);
const hoge = {
name: &#039;aaa&#039;
// ↑compile ok
}
animal.bark();
};
// ↑compile ok
test(hoge);
// ↑ Compile Errorになる


# Page. 23

![Page Image](https://bcdn.docswell.com/page/LE359V5PJ5.jpg)

Generics 型の制約
keyofを使った型の制約
const sample1 = {
name: &#039;Taro&#039;,
age: 10
};
const sample2 = {
Tの型に制限はなし
Uの型はTのObjectのkeyからなるunion型
id: 3,
text: &#039;hoge&#039;
};
function getValue&lt;T, U extends keyof T&gt;(obj: T, key:U): T[U]{
Tにsample1が入る時
Uは &#039;name&#039; | &#039;age&#039;という型になる
return obj[key];
}
console.log(getValue(sample1, &#039;name&#039;)) // 出力:&#039;Taro&#039;
console.log(getValue(sample2, &#039;id&#039;)) // 出力:3
// ↓第２引数は &#039;id&#039; | &#039;text&#039;という型しか受け付けないのでエラーになる
Tにsample2が入る時
Uは &#039;id&#039; | &#039;text&#039;という型になる
console.log(getValue(sample2, &#039;name&#039;))
解説用コード


# Page. 24

![Page Image](https://bcdn.docswell.com/page/8EDDG8D3EG.jpg)

Generics Q4
RequestのBodyかQueryに入っている
共通の検索条件を取り出す関数の型を作る
問題


# Page. 25

![Page Image](https://bcdn.docswell.com/page/V7PX38XPE8.jpg)

Generics A4
Genericsを使って共通化したコード
function getRequestCondParameter&lt;T extends keyof Cond&gt;(body:RequestBody,
query:RequestQuery, key: T): Cond[T] {
const cond: Cond = {
...body.cond,
...query.cond
};
return cond[key];
}
&lt;T extends keyof Cond&gt;
key:T
Cond[T]
TはCondのkeyの文字列のみ受け取る
引数のkeyはkeyof
Condの制約を受けている
interface Cond {
stationId?: string;
}
stationIdを渡せばstring | undeﬁned
lineId?: string;
lineIdを渡せばstring | undeﬁned
money?: number;
moneyを渡せば number | undeﬁned
の型になる


# Page. 26

![Page Image](https://bcdn.docswell.com/page/2JVL4NLV7Q.jpg)

Generics classやinterface
class Queue&lt;T&gt; {
private data:T[] = [];
push(item: T) { this.data.push(item); }
pop(): T | undefined { return this.data.shift(); }
}
const queue = new Queue&lt;number&gt;();
queue.push(0);
queue.push(&#039;hoge&#039;);// error
const queue = new Queue&lt;number&gt;();
Tはnumberで固定される
queue.push(0);
itemの型はnumberになっているため
問題なし
queue.push(&#039;hoge&#039;);
itemの型はnumberになっているため
エラーとなる


# Page. 27

![Page Image](https://bcdn.docswell.com/page/5EGX1KX1JL.jpg)

Generics Q5
平文を暗号化する「Encryptクラス」の
genericsを完成させてください
問題


# Page. 28

![Page Image](https://bcdn.docswell.com/page/4JQ8DN8N7P.jpg)

Generics A5
正解


# Page. 29

![Page Image](https://bcdn.docswell.com/page/K742ZG23J1.jpg)

Genericsを使う意味
結局何が嬉しいのか？


# Page. 30

![Page Image](https://bcdn.docswell.com/page/LJ1MRDMZEG.jpg)

Genericsを使う意味
● コードを型安全に共通化できる
● だから型を間違えているとコンパイルエラーが出る
● そして型を把握できてるので補完が効く


# Page. 31

![Page Image](https://bcdn.docswell.com/page/GJW31Y36J2.jpg)

Genericsを使う意味
今日書いたコードで説明
anyを使ってみて違いを知る
Sample1
Sample2


