TypeScript 勉強会 Day2

284 Views

September 05, 23

スライド概要

社内で行ったTypeScript勉強会のDay2です。Day2 ではジェネリクスをメインに取り扱います。

profile-image

LIFULL HOME'Sを運営する株式会社LIFULLのアカウントです。 LIFULLが主催するエンジニア向けイベント「Ltech」等で公開されたスライド等をこちらで共有しております。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

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

2.

Genericsとは Generics

3.
[beta]
Genericsとは

function test<T>(x: T): T {
return x;
}
const y = test<string>('aaa');

4.

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

5.

Genericsとは 例えば?

6.

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]; } }

7.

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

8.

Generics 型変数 型変数

9.
[beta]
Generics 型変数
function printAndReturn<T>(value: T): T {
console.log(value);
return value;

Q.型変数のTって何?
A.慣習的に型変数にはT,U,Pが使われます。
Tでないとダメというわけではないです。

}

● Tが型変数と呼ばれる部分
○ 何かしらの型が代入されると思ってください
○ 3つのTは全て同一のものです
● <T>が型変数を定義している部分
● valueの型に使われているTと戻り値に書かれているTは定義された型変数を利用している部分

10.

Generics 型引数 型引数

11.
[beta]
Generics 型引数
function printAndReturn(value: number): number {
console.log(value);

function printAndReturn<T>(value: T): T {

return value;

console.log(value);
return value;

}

}
function printAndReturn(value: string): string {
const value1 = printAndReturn<number>(123);

console.log(value);

const value2 = printAndReturn<string>('a');

return value;
}

● <number>が型引数 <T>にnumberを代入しているイメージ
● printAndReturnにnumberの型引数を渡しているので
○ (value: T)のTがnumberになり
○ `: T`の戻り値の型もnumberになる

12.
[beta]
Generics 型引数
function printAndReturn<T>(value: T): T {
console.log(value);
return value;

型引数は型の推論が行われます。
変数の123からTがnumberであることが
推測できるので、省略することが可能で

}

す。

const value = printAndReturn(123);

printAndReturn<number>(123);

123から推論できるので<number>の省略が可能
printAndReturn(123);

14.
[beta]
Generics A1

Genericsを使って共通化したコード
function test<T>(array: T[]):T {
return array[0];

使い方
const array1:string[] = ['a', 'b'];
const array2:number[] = [1,2,3];

}

const a = test(array1);
test<T>

Tは型変数の引数

array: T[]

受け取った型変数の
型の配列を受け取り

:T

受け取った型変数の
型を返す関数

const b = test(array2);

16.
[beta]
Generics A2
Genericsを使って共通化したコード
function myFilter<T>(arr: T[], predicate: (elm: T) => boolean): T[] {
const result = [];
for (const elm of arr) {
if (predicate(elm)) {
result.push(elm);
}
}
return result;
}

myFilter<T>

このTは型変数の定義箇所

array: T[]

Tの配列を受け取り

(elm:T) => boolean

Tをbooleanで判定する関数を受け取る型

: T[]

フィルタリングされたTの配列を返す

18.
[beta]
Generics A3
Genericsを使って共通化したコード
function giveId<T>(obj:T):T & {id:string}{
const id = "本当はランダムがいいけどここではただの文字列";
return {
...obj,
id
};
}

giveId<T>

このTは型変数の定義箇所

obj:T

任意のObjectTを受け取り

T & {id:string}

Tと{id:string}のインターセクション型を返す

19.
[beta]
Generics 型変数(複数)
function printAndReturn<T, U>(value1: T,

● 型引数は複数設定することが可能。

value2: U):(T | U)[] {

● <>に対してカンマ区切りで渡す。

console.log(value1);
console.log(value2);
return [value1, value2];
}
const value = printAndReturn<number,
string>(123, 'aaa');

20.

Generics 型の制約 型の制約

21.
[beta]
Generics 型の制約
interface Animal {
readonly name: string;

型変数であるTが何者かが不明なので
animal.nameの様に呼び出すことができない

bark(): void;
}
function test<T>(
animal: T
) {
console.log(animal.name);
// ↑compile error
animal.bark();
// ↑compile error
}

ただし <T extends hoge> のようにextendsを使っ
て制約をかけることで、呼び出しが可能になる。

22.
[beta]
Generics 型の制約
interface Animal {
readonly name: string;
bark(): void;
}

TがAnimalと互換性のある型という保証があるの
で、animal.nameやanimal.bark();
の呼び出しが可能になる。

function test<T extends Animal>(
animal: T

また下記のような呼び出しは不可能になる

) {
console.log(animal.name);

const hoge = {
name: 'aaa'

// ↑compile ok

}

animal.bark();

};

// ↑compile ok

test(hoge);
// ↑ Compile Errorになる

23.
[beta]
Generics 型の制約
keyofを使った型の制約
const sample1 = {
name: 'Taro',
age: 10
};
const sample2 = {

Tの型に制限はなし
Uの型はTのObjectのkeyからなるunion型

id: 3,
text: 'hoge'
};
function getValue<T, U extends keyof T>(obj: T, key:U): T[U]{

Tにsample1が入る時
Uは 'name' | 'age'という型になる

return obj[key];
}
console.log(getValue(sample1, 'name')) // 出力:'Taro'
console.log(getValue(sample2, 'id')) // 出力:3
// ↓第2引数は 'id' | 'text'という型しか受け付けないのでエラーになる

Tにsample2が入る時
Uは 'id' | 'text'という型になる

console.log(getValue(sample2, 'name'))

解説用コード

24.

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

25.
[beta]
Generics A4
Genericsを使って共通化したコード
function getRequestCondParameter<T extends keyof Cond>(body:RequestBody,
query:RequestQuery, key: T): Cond[T] {
const cond: Cond = {
...body.cond,
...query.cond
};
return cond[key];
}

<T extends keyof Cond>
key:T
Cond[T]

TはCondのkeyの文字列のみ受け取る

引数のkeyはkeyof

Condの制約を受けている

interface Cond {
stationId?: string;

}

stationIdを渡せばstring | undefined

lineId?: string;

lineIdを渡せばstring | undefined

money?: number;

moneyを渡せば number | undefined
の型になる

26.
[beta]
Generics classやinterface
class Queue<T> {
private data:T[] = [];
push(item: T) { this.data.push(item); }
pop(): T | undefined { return this.data.shift(); }
}
const queue = new Queue<number>();
queue.push(0);
queue.push('hoge');// error
const queue = new Queue<number>();

Tはnumberで固定される

queue.push(0);

itemの型はnumberになっているため
問題なし

queue.push('hoge');

itemの型はnumberになっているため
エラーとなる

27.

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

28.

Generics A5 正解

29.

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

30.

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

31.

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