はじめに
他の会社さんを見ていると、TypeScriptを使っているプロジェクトが増えてきて、そろそろマズイなと思っていたところ
ちょうど評判が良さそうな本があったため、読むことにしました!
プロを目指す人のためのTypeScript入門
各章の概要
第1章 イントロダクション
TypeScriptがどういった言語なのかや、どうして生まれたのかといった歴史的経緯を紹介しています。
また、JavaScriptとの関係やTypeScriptを使うことでどういったメリットを持っているのかを学べます。
また、以降の章でサンプルコードを実行するために必要な環境構築もここで行います。
第2章 基本的な文法・基本的な型
変数宣言や演算、制御構文について学びます。
他のプログラミング言語を習得されている方であれば、読み飛ばしても問題ないと思います。
TypeScriptプログラムにおける値はプリミティブとオブジェクトの2種類に大別されます。
オブジェクトは分かりやすいですが、プリミティブって初めて聞きました。
プリミティブは元となる型というイメージで、オブジェクトも中身を見ればプリミティブの組み合わせということになります。
- 文字列
- 数値
- 真偽値
- BigInt
- null
- undefined
- シンボル
第3章 オブジェクトの基本とオブジェクトの型
オブジェクトの特徴や注意点、型の扱いについて学ぶ章になります。
オブジェクトの等価扱いについて、以下のような結果になり驚きました。
const foo = { num: 1234 };
const bar = foo;
const baz = { num: 1234 };
console.log(foo === bar); // true と表示される
console.log(foo === baz); // false と表示される
このような結果になるのは、各プロパティが持つプロパティがたまたま同じだけでオブジェクトとしては異なるものという扱いになるためです。
部分型について
以下の例だと、FooBarが持っているプロパティはFooBarBazも全て持っているから、 FooBarBazはFooBarの部分型といえます。
大は小を兼ねるみたいなイメージでしょうか。
type FooBar = {
foo: string;
bar: number;
}
type FooBarBaz = {
foo: string;
bar: number;
baz: boolean;
}
const obj: FooBarBaz = {
foo: "hi",
bar: 1,
baz: false
};
const obj2: FooBar = obj;
ただ、obj2.bazのように参照しようとすると、FooBar型にはそんな要素はないので、undefinedのチェックをしないとコンパイルエラーになります。
第4章 TypeScriptの関数
関数の基本的な使い方、宣言、関数型について学びます。
関数がどんな型を返すのか定義できるだけで、JavaScriptではチェックしないといけないことが減りそうで良いなと思います。
変数のスコープについて
(TypeScriptに限定した話ではありません)
変数のスコープは以下のような種類があり、上から順に包括関係があります。
- グローバルスコープ
- モジュールスコープ
- 関数スコープ
たとえばtest1という変数を例にすると、以下のような挙動になります。
const test1 = 1;
// 関数スコープからモジュールスコープは参照可能
function sample() {
console.log(test1);//1が出力される
}
// モジュールスコープの変数と同名のものを定義可能
function sample2() {
const test1 = 2;
console.log(test1);
}
// モジュールスコープの変数と同名のものを定義する場合は、定義後でないと使えない
function sample3() {
console.log(test1);
const test1 = 2;
}
ミュータブル(可変、let)な変数を宣言すると、影響範囲を見ていかないといけないですが
関数スコープの中で使っていると範囲が狭く可読性が上がるので意識したいです。
第5章 TypeScriptのクラス
クラス定義の仕方やアクセシビリティ(public,protected,private)についてなどクラスの基本的なことを学べます。
また、アロー関数,try-catch-finalyの解説もあります。
クラスの部分型(implements)
UserクラスはHasName型の部分型であるという宣言を行っている。
type HasName = {
name: string;
}
class User implements HasName {
name: string;
#age: number;
constructor(name: string, age: number) {
this.name = name;
this.#age = age;
}
public isAdult(): boolean {
return this.#age >= 20;
}
}
第6章 高度な型
複数の型を組み合わせて新しい型を作ることができます。
- ユニオン型(string | number) はORのイメージ。stringもしくはnumber型
- インターセクション型(Animal & Human)はANDのイメージ。AnimalとHumanの部分型
typeofで型を取得可能だが、nullに注意
nullをtypeofで調べるとオブジェクトになってしまう。
console.log(typeof "uhyo"); // "string" と表示される
console.log(typeof 26); // "number" と表示される
console.log(typeof {}); // "object" と表示される
console.log(typeof undefined); // "undefined" と表示される
console.log(typeof null); // "object" と表示される
stackoverflowでもアツい議論がされてますが、注意が必要ですね。
https://stackoverflow.com/questions/18808226/why-is-typeof-null-object
オブジェクトを型に変換するための型
Readonly
// T は {
// readonly name: string;
// readonly age: number;
// }
type T = Readonly<{
name: string;
age: number;
}>;
Partial
// T は {
// name?: string | undefined;
// age?: number | undefined;
// }
type T = Partial<{
name: string;
age: number;
}>
Required
// T は {
// name: string;
// age: number;
// }
type T = Partial<{
name: string;
age: number;
}>
Pick<T,K> すでに存在する型から、利用したいプロパティをのみを抽出して新しい型を定義する
// T は {
// age: number;
// }
type T = Pick<{
name: string;
age: number;
}, "age">;
// 複数の時は、こう
type T = Pick<{
name: string;
age: number;
}, "age" | "number">;
Omit<T,K>Pickの逆で、取り除きたいときに使用
// T は {
// age: number;
// }
type T = Pick<{
name: string;
age: number;
}, "number">;
Extract<T,U>Uの部分型であるもののみを抜き出す
type Union = "uhyo" | "hyo" | 1 | 2 | 3;
// T は "uhyo" | "hyo"
type T = Extract<Union, string>;
Exclude<T,U>Uの部分型であるもののみ取り除く
type Union = "uhyo" | "hyo" | 1 | 2 | 3;
// T は 1 | 2 | 3
type T = Exclude<Union, string>;
第7章 TypeScriptのモジュールシステム
npmでモジュールのインストールや、package.json,package-lock.jsonでモジュール管理などを学びます。
TypeScriptでモジュールを使う際は、モジュール自体が型情報付きのものである必要があります。
モジュールの開発体制によっては、対応していないものも多く、有志が作っているシステムを使います。(DefinitelyTypedと@types)
※最近はtsconfig.jsonのallowJsオプションを使うことでインポートすることができるみたいです。
第8章 非同期処理
Promiseやasync/awaitを使った非同期処理を学びます。
非同期処理って、なんとなくやってるけど細かく解説してくれてるので理解が深まりました。
以下のPromiseの静的関数に関しては、実案件でも使う機会があるだろうなと思いました。
2つとも終了するまで待つんだけど、若干動作は違う。
- Promise.all
- どれか1つでも失敗したら即リジェクト
- Promise.allSettled
- 全部終了まで待つ。レスポンスに実行結果が記載されている。
// 成功時 [{ status: "fulfilled", value: 結果の値 }] // 失敗時 [{ status: "rejected", reason: 結果の値 }]
第9章 TypeScriptのコンパイラオプション
tsconfig.jsonで設定できるオプションについて学びます。
歴史的経緯から、制限を緩くすることができるけど、新規のプロジェクトでは制限はデフォルトの状態が望ましいとのことです。
- 全部終了まで待つ。レスポンスに実行結果が記載されている。
おわりに
過去の案件でそこそこの規模のNode.js開発があって、TypeScriptで書いてないことを後悔していたので次からはTypeScriptを使っていきたいと思います。
コメント