仕事ですぐに使えるTypeScript その9

目的

学習の記録と学びになった部分をアウトプットするため。

期限

対象書籍の読了・内容理解が8月中に完了していること。

対象

今回の対象は「基本的な型付け」。

future-architect.github.io

著作権者:フューチャー株式会社(Future Corporation)様

基本的な型付け

一番手抜きな型付け: any

​ - anyを積極的に使用する場合は、すでにJavaScriptとして動作していて実績があるコードをTypeScriptに持ってくる時。 - しかし、anyをする場合はTypeScriptが提供する型チェックの恩恵を受けることはできない。 - TypeScirptではデータが発生する場所で型情報をつければ伝搬されるので、なるべく早く型情報を付けるのが良い。 - 標準ライブラリのfetch関数のレスポンスは外部からのレスポンスになるため、型情報がわからないため、anyとなっている。 ​

未知の型: unknown

​ - 基本的な振る舞いはunknownはanyと似ているが、異なる点としてはunknown型の変数を使用する時に 型アサーションが必要になるということ。 ​

型に名前をつける

​ - type 名前 = で型に名前をつけることができる。 ​ 例 ​

// 複数の型を指定することができる
type BirthMonth = number | string;
const birthMonthNum: BirthMonth = 11;
// > OK
const birthMonthStr: BirthMonth = '11月';
// > OK
<200b>
// 文字列の型も指定することができる。
type redFruits = 'りんご' | 'いちご';
const apple: redFruits = 'りんご';
// > OK
const strawberry: redFruits = 'いちご';
// > OK
<200b>
// 指定した文字以外は代入することができない
const banana: redFruits = 'バナナ';
// > ERROR: TSXXXX

関数のレスポンスや引数で使用するオブジェクトの定義

​ - typeはオブジェクトが保持すべき属性の定義も使用することができる。 ​

type Person = {
  name: string,
  favorite: string,
  old: number
}
<200b>
const p: Person = {
  name: '佐藤',
  favorite: 'ハリーポッター',
  old: 30
}
<200b>
// 上記のように型定義をしておくと、オブジェクトを生成した時に項目が不足している場合は、エラーが発生する。
const p: Person = {
  name: '鈴木'
}
};
// error TS2741: Property 'favorite' is missing in
//   type '{ name: string; }' but required in type 'Person'.

オブジェクトの属性の就職: オプション、読み込み専用

  • オブジェクトの型定義を行う際に、名前の前にreadonly を付与することで、属性の値が読み込み専用になり、書き込もうとするとエラーにすることができる。
  • また、名前の後ろに?(クエスチョンマーク)をつけtることで、そのオブジェクトでは省略可能な属性であることを示すことができる。 ​
type Person = {
  name: string,
  readonly personID: number,
  old?: number
}

型ユーティリティー

​ - Partial を利用することで、一度定義した型のすべての属性に一括して?(クエスチョンマーク)をつけて任意項目にすることができる。 ​

type Person = {
  name: string,
  favorite: string,
  old: number
}
<200b>
const p: Partial<Person> = {
  name: 'hogehoge'
}
// > Partialユーティリティを使用しているので、name, favorite, oldにはクエスチョンマークが付いている状態になっている。
// > すべて任意項目なので、オブジェクトを生成するときは指定しなくてもOKになる。
<200b>
const p: Readonly<Person> = {
  name: 'hoge',
  favorite: 'fuga',
  old: 30
}
p.name = 'can not change';
// > Cannot assign to 'favorite' because it is a read-only property.

属性名が可変のオブジェクトを扱う

  • 基本的に辞書型のようなオブジェクトを使用したい場合は、Mapを使用したりイテレータを使用することが多いですが、外部システムとの連携の兼ね合いから辞書型で返却される場合があるので、そういった場合は下記のように型定義を書くことで辞書のように扱われるオブジェクトの宣言を行うことができる。
  • 下記では郵便番号のハイフンを抜くことでkeynumber型で宣言することができる。しかしながら、そもそもJavaScriptのオブジェクトのキーは文字列型(string)のため、キーをObject.keys()等で抜き出したときは、number型ではなくstring型になることに注意する。 ​
const postalCodes: { [key: string]: string } = {
  '100-0000': '東京都千代田区',
  '200-0000': '千葉県千葉市',
  '300-0000': '茨城県つくば市'
}

AかつBでなければならない型定義

- 下記のように&(アンパサンド)で型定義を行うものを交差型と呼ばれている。

type Apple = {
  appleID: string
}
<200b>
type Facebook = {
  facebookID: string
}
<200b>
const ID: Apple & Facebook = {
  appleID: 'hoge@icloud.com',
  facebookID: 'fuga@facebook.com'
}

タグ付き合併型: パラメータの値によって必要な属性が変わる柔軟な型定義を行う

​ 直近すぐに業務に必要になりそうなことはなさそうなので、後日読む ​ https://future-architect.github.io/typescript-guide/typing.html#id7

型ガード

​ - そもそも型ガードとはなにか、それは型を「数字型 or 文字列型」で定義した時など、複数の型の変数を扱う場合に、この型の場合はこのロジックを適用したい、というもの。 - TypeScriptは型情報を除くとJavaScriptになる。TypeScriptのコンパイラが保持するインターフェースやtypeなどは、実行時のランタイムには存在脚ないので、このオブジェクトがこのインターフェースを保持しているとき、という実行文は記述することができない。 - これを解決するため、TypeScriptでは型ガードという機能がある。 - typeof は変数の型名をstringで返す。

let userNameOrId: string | number;

if (typeof userNameOrId === "string") {
  console.log("string")
} else {
  const id = this.repository.getUserName(userNameOrId);
  console.log(id);
}

アサーション

  • TypeScriptには型アサーションという機能がある。他言語でいうところのキャストである。(asを後置する)
  • これはコンパイラのもつ型情報を上書きするもので、実行時に情報を一切参照せずにただ変数の方を変更する。
const page: any = { name: "sample page" }
const name: string = page as string;