427 Views
September 26, 23
スライド概要
社内で開催した TypeScript 勉強会の Day3 スライドです。Day1 で扱った内容の応用編などを掲載しています。
LIFULL HOME'Sを運営する株式会社LIFULLのアカウントです。 LIFULLが主催するエンジニア向けイベント「Ltech」等で公開されたスライド等をこちらで共有しております。
TypeScript ハンズオン Day3 Fukudome Naohiro 1 © LIFULL Co.,Ltd. 本書の無断転載、複製を固く禁じます。
今日のおしながき ● ユニオン型とinキーワード ○ day 1の「ユニオン型」の応用編 ● ユーザー定義型ガード ○ day 1の「型ガード」の応用編 ● Utility Types ○ ジェネリクスを使ったいろんな組み込み型
ユニオンとinキーワード
ユニオン型のおさらい type Id = string | number 既存の型の組み合わせで新しい型を作る Day1資料
オブジェクトの型定義 type MyObject = { keyがstringかnumber、 [Key: string | number] : string } valueがstringのオブジェクト
primitive型以外でやっていきたい //翻訳の対応表の型 type Translate = { [SupportLang: "en" | "ja" | "es" | "de"] : string } //翻訳の具体的な対応表 const translations: Translate = { "en": "Hello", "ja": "こんにちは", "es": "Hola", "de": "Guten Tag", // ↓対応してない言語ではエラーになってほしい "fr": "Bonjour" }
残念ながら //対応している言語 type Translate = { // ↓でエラー [SupportLang: "en" | "ja" | "es" | "de"] : string } //翻訳の対応表 const translations: Translate = { "en": "Hello", "ja": "こんにちは", "es": "Hola", "de": "Guten Tag", // ↓対応してない言語ではエラーになってほしい "fr": "Bonjour" }
そんなあなたに inキーワード✨
in ユニオン型に対して type Translate = { [Lang in "en" | "ja" | "es" | "de"] : string 1つずつの繰り返しを表す } => コードの例
注意
const car = { make: 'Honda', model: 'Accord', year: 1998 };
// carにmakeプロパティがなければ表示
if ('make' in car !== false) {
if文で使う in とは異なる概念
console.log('どこでつくられたのかわかりません')
}
あくまで型の世界で使う
ユーザ定義型ガード
おさらい: 型ガード
function numberOrString(someArg: string | number) {
if (typeof someArg === 'number') {
console.log('変数の型はnumberです');
} else {
console.log(`変数の型は${typeof someArg}です`)
}
}
numberOrString(1) // => "変数の型はnumberです"
numberOrString("str") // => "変数の型はstringです"
変数の型によって
処理を分岐できる機能
おさらい: うれしいこと
/**
* 文字列の末尾に"co.jp"を付けくわえる関数
stringではないものに
*/
function tld(domain: string | undefined): string {
if (typeof domain === 'string') {
return domain.concat('.co.jp');
stringのメソッドを使おうとしたとき弾いて
くれる
} else {
// ↓ domainがstringではない => domainはundefined
//
=> concatは存在しない => コンパイルエラー
return domain.concat('.co.jp');
}
}
Playground
自分で定義した型でガードしたい type Foo = { foo: number; common: string; } type Bar = { bar: number; common: string; } function doStuff(arg: Foo | Bar) { if (typeof arg === "Foo") { // argがFoo型だったときの処理 // Fooにしかない値を使いたい console.log(arg.foo); } } 自分で作った型を使って型ガードしたい
自分で定義した型でガードしたい
type Foo = {
foo: number;
common: string;
}
残念ながらコンパイルエラーになる
=> Playground
type Bar = {
bar: number;
common: string;
}
エラーメッセージ
function doStuff(arg: Foo | Bar) {
if (typeof arg === "Foo") {
// argはFoo型やな! => エラー
console.log(arg.foo);
}
}
(要約: Fooはtypeofの返り値の型にはありません)
This comparison appears to be unintentional because
the types '"string" | "number" | "bigint" | "boolean"
| "symbol" | "undefined" | "object" | "function"' and
'"Foo"' have no overlap.
そんなあなたに isキーワード✨
ユーザ定義型ガード type Foo = { foo: number; common: string; } type Bar = 省略 // 関数の返り値が true なら仮引数 arg の型は Foo function isFoo(arg: any): arg is Foo { is キーワードで関数を型定義 return arg.foo !== undefined; 中身はbooleanを返すよう実装する } function doStuff(arg: Foo | Bar) { if (isFoo(arg)) { // argはFoo型に確定する console.log(arg.foo); console.log(arg.bar); // barはFooにないのでコンパイルエラー } }
注意 type Foo = { foo: number; common: string; ユーザ定義型ガード用の } function doStuff(arg: Foo | Bar) { // コンパイルエラー if (arg is Foo) { ... } } 関数の型定義だけにしか使えない
クラスと組み合わせてみましょう type Result = Success | Failure // 何らかの処理を行って、SuccessかFailureを返す function doSomething(x: boolean): Result { if (x) { return new Success('success') } else { Result型はSuccessかFailureのどっちか return new Failure('failure') } } SuccessのときとFailureのときで処理を分 const result = doSomething(true) けたいとき if (result.isFailure()) { // 異常系の処理... } else { あると思います // 正常系の処理... }
Utility Types
Utility Types ジェネリクスを活用した 便利な組み込み型 一覧
Pick
Pick型 Pick<T, K> あるオブジェクト型Tから、 Kで指定されたキーだけを取り出す型
例題に困ったので いろんな型パズルが楽しめるリポジトリ type-challenges
デバッグの際には ^? を中身を知りたいところに合わせて書いてみましょう