実践 TypeScriptの読書MEMO1
最近、実践 TypeScriptを読んでいるので読書メモです。
実践TypeScript ~ BFFとNext.js&Nuxt.jsの型定義~
- 作者:吉井 健文
- 発売日: 2019/06/26
- メディア: 単行本(ソフトカバー)
私の知らなかったことをたくさん書いてます。
どんな本
- TypeScript特有の知識を体系的に学ぶための1冊
- 集中してTypeScriptの型定義を深く学べる
- 1部は基礎知識、2部は理解を深める
- 2部は実践的にJavascriptフレームワークやライブラリ(React、Vue.js等)におけるTypeScript の導入
- TypeScriptを導入するメリット
- 分割されたモジュール同士の依存関係を担保する
- 型システムが、バックエンドからフロントエンドの末端のviewまで一環して不整合ないデータの橋渡しを実現する
目的
- TypeScriptの型定義きちんと理解したい
- 型定義ははじめてなので…
- 最終的にTypeScriptを実践的に使えるようになりたい
- 先輩のTypeScriptのコードをちゃんと理解できるようになりたい
- 4章5章をちゃんと読んでTypeScriptのコンパイルエラーの解決慣れしたい
- コンパイルエラーの解決に時間がかかってしまう…
1. 開発環境と設定
1-1. tsconfig.json
TypeScriptコンパイラーの設定ファイル。
tsc --init
で作成
tsconfig.json
{ // teconfig.jsonの初期値 "compilerOptions": { "target": "es5", "module": "commonjs", "strict": true, "esModuleInterop": true }
target
トランスパイル後のECMAScriptのターゲットバージョン。
- es5
- es2015
- esnext
module
コード生成モジュールを指定
- commonjs
- amd
define()
に配列でモジュール名を指定する
strict
型の厳密さを一括して指定
一括で有効になるのは以下の指定
- noImplicitAny
- noImplicitThis
- alwaysStrict
- strictBindCallApply
- strictNullChecks
- strictFunctionTypes
- strictPropertyInitialization
1-2. 型宣言ファイルの出力
関数定義などの型を通達するために、型宣言ファイル(.d.ts
)が利用できる
.d.ts
いつ使うんだろう🤔
- 型情報が消えしまう
.d.ts
は型定義が分かる- JavaScriptで書かれたライブラリには型情報がない…
- ライブラリ等で使うときは型定義ファイルがあれば、みんなが幸せになれる
1-3. ライブラリの型定義を利用する
npmで配信されているライブラリには、TypeScriptの型定義が存在するものとしないものがある。
DefinitelyTyped
TypeScript型定義ファイル(dts)を用意していないJSライブラリのための型定義ファイル集 @typesで始まるパッケージ
2. TypeScriptの基礎
TypeScriptのもっとも基本的な用語の呼称・利用方法についての章。
2-1. JavaScriptの課題
1. 引数に数値として扱うことのできない値を渡してしまいNaN
が表示されてしまう
- 引数を型注釈で制約する
function expo2(amout: number){ return amout ** 2 }
2. 計算の途中、数値が文字列に変換されてしまいNaN
が返ってくる
function fee(amount): number { return amount * 1.4 }
2-2. 基本の型
(私の知らなかった型をまとめてます。)
- tuple型
- 固定数の要素がわかっている配列を表現できる
- 配列の要素ごとに型が違うデータ型が定義できる。
let x: [string, number]
- any型
- 型の不明な変数を扱うことがある場合に使用することで型チェックを無効にし、コンパイルを通過させる
- TypeScriptの恩恵を受けることはできないので、できる限りany型が現れないコードを書き、型安全なプロジェクトを目指す。
- unknown型
- any型に似ているが、型安全なanyを表したいときに利用する
- void型
- any型の反対のようなもの。型が全くないことを表す。
- 一般に、値を返さない関数の戻り値として利用
- never型
- 発生し得ない値の型を表す
- 返り値が無いことを表すvoid型とは異なり、そもそも関数が正常に終了して値が返ってくるということがあり得ない場合
function func(): never { throw new Error('Hi'); } const result: never = func();
- object型
- 非プリミティブ型
{}
を使った型表現ではエラーを得ることができない
2-3. 高度な型
- Intersection Types
- 複数の型を一つに結合する
- Union Types
- Union Types(共用体)は複数の型のうち一つの型が成立することを示している。
let value: boolean | number | string
- array型を含む要素をUnion Typesにする場合
let numberOrString: (number | string)[]
- Nullable型を表現できる
let nullableString: string | null
- Union Types(共用体)は複数の型のうち一つの型が成立することを示している。
- Literal Type
2-5. アサーション
任意の型に変換することができる。
型アサーションは2種類の書き方がある。
<変換したい型>値
値 as 変換したい型
let text: any = "this is a string"; let textLength: number = (<string>text).length;
let text: any = "this is a string"; let textLength: number = (text as string).length;
↑ 文字列の文字数を取得するために string に変換して length を呼び出している
<>
ではJSXタグとの区別が曖昧になるため、非推奨
2-6. 列挙型
enumを使用すると、列挙型を定義できる。 列挙している属性以外が入ってくると怒ってくれる
3. TypeScriptの型安全
バグを減らすことはTypeScriptを導入する大きな理由の一つであり、
TypeScriptを使いこなすようになるほど、絞り込むという作業がバグを減らす上でいかに重要な作業かということに気づくらしい。
3-1. 制約による型安全
- アノテーションを用いると、引数や変数定義において、誤った値の代入を防げる。
null
,undefined
- 早期return(ガード節、Type Guard)
- Weak Type
- すべてのプロパティがオプショナルな型
3-2. 抽象度による型安全
- 抽象的な型は広く値を受け付けることができる
- 詳細な型は担保された制約の下で処理を安全に展開できる
- 抽象的な型・詳細な型がどのようなものであるかを理解し、抽象度をコントロールすることが必要
- キャスト
- 変数の型を別の型へ変換すること
- ダウンキャスト
- 抽象的な型から詳細な型を付与すること(互換性があるときのみ可能、互換性がない場合は成立しない)
- アップキャスト
- 抽象度をあげる
- インデックスシグネチャ
- 任意のプロパティを動的に追加することが可能
- 危険な型の付与
- Non-null assertion
- double assertion
4. TypeScriptの型システム
バグを減らすことはTypeScriptを導入する大きな理由の一つ。
TypeScriptを使いこなすようになるほど、絞り込むという作業がバグを減らす上でいかに重要な作業かということに気づくらしい。
4-1. 型の互換性
any型の互換性
- どんな型にも宣言・代入できる。
- any型は、どのように扱おうとも危険な型
unknown型の互換性
- unknown型は、どんな型の値も受け入れることができるTopTypeであり、型の中でもっとも抽象的な型。
- any型とは異なり安全に扱うことができる型
- unknown型の値はどんな値なのか分からないため、できることが制限されている。 - (任意の値を代入できる点はany型と同じ、型アサーション等が無いと利用できない。)
{}型の互換性
- 型に互換性がありため、いずれもコンパイルエラーにはならない。
{}
という型はオブジェクト以外も受け付けてしまう。(ただし、undefinedとnullはだめ)- プリミティブ型は{}型のサブタイプ
5. TypeScriptの高度な型
Generics
基本的な付与
Genericsを利用する型の宣言
interface Box<T> { value: T }
const box0: Box = { value: 'test' } // Error! Genericsを指定していない const box1: Box<string> = { value: 'test' } const box2: Box<number> = { value: 'test' }// Error! Number型ではない
実践TypeScriptの読書MEMO2に続きます。