TypeScript
本書『サバイバルTypeScript』は実務でTypeScriptを使う開発者のための入門書です。そして、このページはTypeScriptの特徴を最速で把握できるよう、数百ページからなる本書のコンテンツをつまみ食いした要約です。
TypeScriptとは
- JavaScriptのスーパーセットとなるプログラミング言語。
- 静的型付け言語であり、プログラムの正しさが静的に検査できる。
- ライブラリやIDEなどの開発環境が充実しており、大きなエコシステムを持っている。
- Microsoftが2012年に開発し、オープンソースで公開した。
» TypeScriptの特徴について詳しく知る
» TypeScript誕生の背景について詳しく知る
TypeScriptはJavaScriptのスーパーセット
- スーパーセットとは、元の言語との互換性を保ちつつ、元の言語を拡張して作った言語のこと。
- TypeScriptは、JavaScriptとの互換性を保ちつつ、JavaScriptを拡張して作った言語である。
- よって、JavaScriptのコードはすべてTypeScriptとしてあつかえる。
- TypeScriptは、型注釈やインターフェース、ジェネリクスなど独自の機能を追加している。
スーパーセットのメリット
- 学習のしやすさ: JavaScriptの知識を活かしてTypeScriptを学べる。
- 資産が活かせる: 既存のJavaScriptコード資産を活かして開発できる。
- 移行のしやすさ: 既存のJavaScriptプロジェクトはTypeScriptへ移行がしやすい。
» TypeScriptとJavaScriptの関係について詳しく知る
静的な検査
- TypeScriptはプログラムの正しさを静的に検査できる。
- JavaScriptは実行しないとバグがあるかを確かめられない。
- TypeScriptは実行せずにチェックが行える。
開発効率と品質を向上し、安心感を高める
- 問題を早期に発見し、開発を効率化できる。
- コーディング時に問題を発見し、修正できるため、バグを予防できる。
- エディターとTypeScriptを連携させると、リアルタイムのチェックやコード補完が可能。
- 問題を早期に修正できることで、製品の信頼感や安心感が高まる。
- 見通しの悪い大規模なプログラムや、重要なシステムの開発では静的な検査が安心材料になる。
検査の仕組み
- TypeScriptの検査は型システムに基づく。
- 型システムに基づき、コンパイルのタイミングでプログラムを検査する。
型システム
- 型システムは、データの種別ごとに型を与え、データに対して行える操作に制約を設ける。
- これにより、変数には決められた値のみが代入され、決められた操作のみが行われることが保証され、プログラムが正確で安全になる。
- 型システムは、数学の「型理論」を背景に構築され、数学的証明によりプログラムの欠陥をあぶり出せる。
型注釈
- 変数にどのような値が代入できるのかを制約するものを「型」と言う。
- 開発者は、変数がどのような型なのかを型注釈で指定する。
- TypeScriptでは、型注釈を手がかりに検査が行われる。
型推論
- 値の型が文脈で明白な場合、型が自動で判断される。この仕組みを型推論という。
- 型推論のおかげで、開発者は型注釈を割愛でき、記述量を減らせる。
コンパイル
- TypeScriptを実行するために、JavaScriptへ変換する。この変換のことをコンパイルという。
- 変換後のJavaScriptコードはブラウザやサーバーで実行できる。
- TypeScriptの検査はコンパイルのタイミングで行われる。
型はドキュメント、リファクタリング、ツールの充実にも寄与
- ドキュメントになる: 型情報はドキュメントの役割を果たし、コードの理解を助ける。
- リファクタリングが安全に: 変数の型や関数のシグネチャを変更したとき、修正が必要な箇所がコンパイル時にすべて分かり、不注意による誤修正を減らせる。
- ツールサポートが充実: IDEやエディターでのリアルタイムのエラーチェック、自動補完、リファクタリングツール、ナビゲーションなど、開発ツールのサポートが充実している。
多くのエディターがTypeScriptをサポート
- Visual Studio Code
- JetBrains IDE (IntelliJ, WebStorm, PhpStorm, RubyMine, PyCharm, GoLandなど)
- Vim
- NeoVim
- Emacs (Tide)
- Atom
- Sublime Text
多様なソフトウェアが作れる
作れるものの範囲が広いことは、TypeScriptの魅力のひとつ。
- Webアプリケーション: TypeScriptの主戦場。フロントエンドの開発に広く使用される。
- サーバーサイドアプリケーション: Node.jsと組み合わせて、バックエンドやAPIサーバーを開発することが可能。
- モバイルアプリケーション: React Nativeなどのフレームワークを利用して、モバイルアプリケーションを開発できる。
- デスクトップアプリケーション: Electronを使用して、クロスプラットフォームのデスクトップアプリを開発できる。
- クラウド関連の機能: AWS LambdaやAzure Functionsなどのクラウドプラットフォームで、サーバーレス関数が作成できる。
- ユーティリティーやCLIツール: コマンドラインツールや各種ユーティリティの開発ができる。
- インフラ構成管理(IaC): PulumiやAWS CDKを使用して、インフラの構成を管理することができる。
- アプリケーションの拡張機能: Google ChromeやVisual Studio Codeなどデスクトップアプリケーションの拡張をTypeScriptで開発できる。
TypeScriptを導入した企業の感想
- Slack: コードベースが大規模になっても、型システムが安全性と信頼性を保証してくれる。
- Airbnb: TypeScriptを使っていたらAirbnbの38%ものバグを未然に防げた。
- ヤフー株式会社: 静的型付けによりコードの品質とメンテナンス性が向上し、IDEとの連携により開発者の生産性が向上した。
- LINE株式会社: ちょっとした修正でもかかるQAのコストを、TypeScript化によって抑制。
- Sansan株式会社: 型がドキュメントとしての役割を果たし、コードリーディングや他チームのコード変更に役立った。採用の文脈でアピールポイントにもなった。
- ラクスル株式会社:型システムの恩恵が得られる、エディターの入力補完を受けられる、コード=ドキュメントという状況を作りやすい。
基本的な型
プリミティブ型
boolean
: 真偽値。number
: 数値。string
: 文字列。bigint
: 大きな整数。symbol
: 一意の値を示す。undefined
: 値が定義されていない状態を示す。null
: 値が存在しない状態を示す。
typescript
constisReady : boolean = false;constage : number = 25;constfullName : string = "John Doe";constbigNumber : bigint = 100n;constuniqueSymbol : symbol =Symbol ("unique");constnotDefined : undefined =undefined ;constempty : null = null;
typescript
constisReady : boolean = false;constage : number = 25;constfullName : string = "John Doe";constbigNumber : bigint = 100n;constuniqueSymbol : symbol =Symbol ("unique");constnotDefined : undefined =undefined ;constempty : null = null;
特殊な型
any
: 何でも代入できる型。型が不明な場合に使用する。その値に対する操作の制限がなく、型の安全性は弱まる。unknown
: any型と似て、何でも代入できる型。その値に対する操作は制限され、型の安全性が保たれる。void
: 値が存在しないことを示す。関数が何も返さない場合に使用する。never
: 決して何も返さないことを示す。エラーを投げる関数や無限ループの関数の戻り値として使用する。
typescript
consta : any = 100; // 代入できるconsole .log (a * 3); // 操作もできるconstx : unknown = 100; // 代入はできる'x' is of type 'unknown'.18046'x' is of type 'unknown'.console .log (* 3); // 操作はできない x // 戻り値のない関数functiondoSomething (): void {}// 戻り値を返すことがありえない関数functionthrowError (): never {throw newError ();}
typescript
consta : any = 100; // 代入できるconsole .log (a * 3); // 操作もできるconstx : unknown = 100; // 代入はできる'x' is of type 'unknown'.18046'x' is of type 'unknown'.console .log (* 3); // 操作はできない x // 戻り値のない関数functiondoSomething (): void {}// 戻り値を返すことがありえない関数functionthrowError (): never {throw newError ();}
型エイリアス
- 型エイリアスは既存の型を新たな名前で定義する機能。
- より複雑な型を簡素に表現したり、コードの可読性を向上するのに役立つ。
typescript
typeStringOrNumber = string | number;letvalue :StringOrNumber ;value = "hello"; // string型が代入可能value = 123; // number型も代入可能
typescript
typeStringOrNumber = string | number;letvalue :StringOrNumber ;value = "hello"; // string型が代入可能value = 123; // number型も代入可能
構造的部分型
- TypeScriptは構造的部分型を採用している。
- 構造的部分型では、変数の代入可否を、構造が互換しているかに着目して判定する。
typescript
typeSummary = {name : string };typeDetail = {name : string;age : number };constjohnDetail :Detail = {name : "John",age : 28 };constsummary :Summary =johnDetail ; // 代入できる。構造的部分型として互換があるためconstjohnSummary :Summary = {name : "John" };constProperty 'age' is missing in type 'Summary' but required in type 'Detail'.2741Property 'age' is missing in type 'Summary' but required in type 'Detail'.: detail Detail =johnSummary ; // 代入できない。構造的部分型として互換がない(ageを含まないため)
typescript
typeSummary = {name : string };typeDetail = {name : string;age : number };constjohnDetail :Detail = {name : "John",age : 28 };constsummary :Summary =johnDetail ; // 代入できる。構造的部分型として互換があるためconstjohnSummary :Summary = {name : "John" };constProperty 'age' is missing in type 'Summary' but required in type 'Detail'.2741Property 'age' is missing in type 'Summary' but required in type 'Detail'.: detail Detail =johnSummary ; // 代入できない。構造的部分型として互換がない(ageを含まないため)
配列
配列リテラル
- 配列の値を作るには配列リテラル(
[]
)を使う。 [要素1, 要素2, ...]
の形で配列の初期値を設定できる。
typescript
constnumbers = [1, 2, 3];
typescript
constnumbers = [1, 2, 3];
配列の型注釈
- 配列の型注釈には
型名[]
またはArray<型名>
を使う。
typescript
letnumbers : number[];letstrings :Array <string>;
typescript
letnumbers : number[];letstrings :Array <string>;
配列要素へのアクセス
- 配列要素にアクセスするにはインデックス(インデックス)を使う。
- 0から始まる整数を指定して配列の値を取得し、代入も可能。
typescript
constcolors = ["red", "green", "blue"];console .log (colors [0]);colors [1] = "yellow";console .log (colors );
typescript
constcolors = ["red", "green", "blue"];console .log (colors [0]);colors [1] = "yellow";console .log (colors );
読み取り専用配列
- 読み取り専用配列は値の変更ができない配列を表す。
- 配列の型注釈に
readonly
をつけると読み取り専用配列となる。 ReadonlyArray<型名>
でも読み取り専用配列が宣言でき、readonly 型名[]
と機能は同じ。
typescript
constnumbers : readonly number[] = [1, 2, 3];conststrings :ReadonlyArray <string> = ["hello", "world"];Index signature in type 'readonly number[]' only permits reading.2542Index signature in type 'readonly number[]' only permits reading.numbers [0] = 4; // 値を変更できないProperty 'push' does not exist on type 'readonly string[]'.2339Property 'push' does not exist on type 'readonly string[]'.strings .("!"); // 要素を追加できない push
typescript
constnumbers : readonly number[] = [1, 2, 3];conststrings :ReadonlyArray <string> = ["hello", "world"];Index signature in type 'readonly number[]' only permits reading.2542Index signature in type 'readonly number[]' only permits reading.numbers [0] = 4; // 値を変更できないProperty 'push' does not exist on type 'readonly string[]'.2339Property 'push' does not exist on type 'readonly string[]'.strings .("!"); // 要素を追加できない push
配列のループ
- 配列をループするための
for...of
構文もある。
typescript
constnumbers = [1, 2, 3];for (constnum ofnumbers ) {console .log (num ); // 1, 2, 3と出力される}
typescript
constnumbers = [1, 2, 3];for (constnum ofnumbers ) {console .log (num ); // 1, 2, 3と出力される}
タプル型
- タプル型を使うと、配列の要素数と要素の型が固定される。
- それぞれの要素のインデックスごとに型が決まる。
typescript
lettuple : [string, number];tuple = ["hello", 10]; // 代入できるType 'number' is not assignable to type 'string'.tuple = [10 ,"hello" ]; // 順序が正しくないため、代入できない
Type 'string' is not assignable to type 'number'.2322
2322Type 'number' is not assignable to type 'string'.
Type 'string' is not assignable to type 'number'.Type '[string, number, string]' is not assignable to type '[string, number]'. Source has 3 element(s) but target allows only 2.2322Type '[string, number, string]' is not assignable to type '[string, number]'. Source has 3 element(s) but target allows only 2.= ["hello", 10, "world"]; // 要素が多すぎるため代入できない tuple
typescript
lettuple : [string, number];tuple = ["hello", 10]; // 代入できるType 'number' is not assignable to type 'string'.tuple = [10 ,"hello" ]; // 順序が正しくないため、代入できない
Type 'string' is not assignable to type 'number'.2322
2322Type 'number' is not assignable to type 'string'.
Type 'string' is not assignable to type 'number'.Type '[string, number, string]' is not assignable to type '[string, number]'. Source has 3 element(s) but target allows only 2.2322Type '[string, number, string]' is not assignable to type '[string, number]'. Source has 3 element(s) but target allows only 2.= ["hello", 10, "world"]; // 要素が多すぎるため代入できない tuple
タプルの要素へのアクセス
- タプルの要素にアクセスする場合も配列同様にインデックス(インデックス)を使用する。
typescript
consttuple : [string, number] = ["hello", 10];console .log (tuple [0]);
typescript
consttuple : [string, number] = ["hello", 10];console .log (tuple [0]);
オブジェクト
オブジェクトリテラル
- オブジェクトの作り方はオブジェクトリテラル(
{}
)を使う。 { プロパティキー: 値, ... }
の形でオブジェクトの初期値を設定できる。
typescript
constjohn = {name : "John",age : 20 };
typescript
constjohn = {name : "John",age : 20 };
プロパティアクセス
- ドット
.
を使ってオブジェクトのプロパティにアクセスできる。
typescript
console .log (john .name );
typescript
console .log (john .name );
オブジェクトの型注釈
- オブジェクトの型注釈は
{プロパティ1: 型1, プロパティ2: 型2, ...}
の形で記述する。
typescript
letobj : {name : string;age : number };
typescript
letobj : {name : string;age : number };
readonlyプロパティ
readonly
をつけたプロパティは代入できない。
typescript
letobj : { readonlyname : string;age : number };obj = {name : "John",age : 20 };Cannot assign to 'name' because it is a read-only property.2540Cannot assign to 'name' because it is a read-only property.obj .= "Tom"; name
typescript
letobj : { readonlyname : string;age : number };obj = {name : "John",age : 20 };Cannot assign to 'name' because it is a read-only property.2540Cannot assign to 'name' because it is a read-only property.obj .= "Tom"; name
オプションプロパティ
- オプションプロパティ
?
をつけたプロパティは省略可能。
typescript
letobj : {name : string;age ?: number };obj = {name : "John" }; // `age`プロパティがなくてもエラーにならない
typescript
letobj : {name : string;age ?: number };obj = {name : "John" }; // `age`プロパティがなくてもエラーにならない
オブジェクトメソッド
- 関数をプロパティに持つオブジェクトを定義できる。
typescript
constobj = {a : 1,b : 2,sum (): number {return this.a + this.b ;},};console .log (obj .sum ());
typescript
constobj = {a : 1,b : 2,sum (): number {return this.a + this.b ;},};console .log (obj .sum ());
インデックス型
- オブジェクトはインデックス型を利用して任意のキーの値を取得することができる。
- インデックス型プロパティの型注釈は
[キー名: プロパティキーの型]: プロパティ値の型
の形で記述する。
typescript
letobj : { [key : string]: number };obj = {key1 : 1,key2 : 2 };console .log (obj ["key1"]);console .log (obj ["key2"]);
typescript
letobj : { [key : string]: number };obj = {key1 : 1,key2 : 2 };console .log (obj ["key1"]);console .log (obj ["key2"]);
Shorthand property names
- プロパティの値がすでに定義されている変数である場合、そのプロパティ名を省略して記述できる(shorthand property names)。
typescript
constname = "John";constage = 20;constobj = {name ,age };console .log (obj );
typescript
constname = "John";constage = 20;constobj = {name ,age };console .log (obj );
オプショナルチェーン
- プロパティが存在するかどうか不確定である場合、
?.
演算子(オプショナルチェーン)で安全にアクセスできる。
typescript
functionprintLength (obj : {a ?: string }) {console .log (obj .a ?.length );}printLength ({a : "hello" });printLength ({});
typescript
functionprintLength (obj : {a ?: string }) {console .log (obj .a ?.length );}printLength ({a : "hello" });printLength ({});
Map
Mapオブジェクト
- Mapオブジェクトはキーとそれに対応する値を対にしたコレクション。
- キーはオブジェクトも含め任意の値が可能。
typescript
constmap = newMap ();map .set ("name", "John");map .set ("age", "20");console .log (map .get ("name"));
typescript
constmap = newMap ();map .set ("name", "John");map .set ("age", "20");console .log (map .get ("name"));
Mapの型注釈
- Mapの型注釈は
Map<キーの型, 値の型>
の形で記述する。
typescript
letpeople :Map <string, number>;
typescript
letpeople :Map <string, number>;
Mapのループ
- Mapオブジェクトは
for...of
でループすると、各エントリーがキーと値の配列として順に取得できる。 - 要素の順序は、要素を追加した順が保証されている。
typescript
for (const [key ,value ] ofmap ) {console .log (key ,value );}
typescript
for (const [key ,value ] ofmap ) {console .log (key ,value );}
Set
Set オブジェクト
- Setオブジェクトは同じ値が存在しないコレクション。
- Setの要素は何でも可能である。
typescript
constset = newSet ();set .add (1);set .add (2);set .add (2); // 同じ値は追加されない。console .log (set );
typescript
constset = newSet ();set .add (1);set .add (2);set .add (2); // 同じ値は追加されない。console .log (set );
Setの型注釈
- Setの型注釈は
Set<要素の型>
の形で記述する。
typescript
letnumSet :Set <number>;
typescript
letnumSet :Set <number>;
Setのループ
- SetもMap同様に
for...of
でループすることが可能。 - 順序は
add
した順。
typescript
for (constvalue ofset ) {console .log (value );}
typescript
for (constvalue ofset ) {console .log (value );}
列挙型 (Enum)
列挙型の基本
- 列挙型(enum)は、関連する一連の数値または文字列値の集まりを定義する。
- 列挙型は
enum
キーワードを使用して定義する。
typescript
enumColor {Red ,Green ,Blue ,}
typescript
enumColor {Red ,Green ,Blue ,}
列挙型に値を設定
- 列挙体の値は文字列リテラルまたは数値リテラルで指定できる。
typescript
enumColor {Red = "red",Green = "green",Blue = "blue",}
typescript
enumColor {Red = "red",Green = "green",Blue = "blue",}
列挙型の利用
- 列挙型の各値にアクセスするにはドット演算子を使用する。
typescript
constmyColor :Color =Color .Red ;
typescript
constmyColor :Color =Color .Red ;
ユニオン型
- ユニオン型は複数の型のうちのいずれかをとる値を表現できる。
型1 | 型2 | ...
の形式で使う。- ひとつ以上の異なる型の値を同じ変数で扱う場合に使用する。
typescript
letvalue : boolean | number;value = true; // 代入できるvalue = 100; // 代入できる
typescript
letvalue : boolean | number;value = true; // 代入できるvalue = 100; // 代入できる
判別可能なユニオン型
- 判別可能なユニオン型は、共通のリテラル型のプロパティを持つ特別なユニオン型。
- 共通のプロパティを利用して、型を判別できる。
typescript
typeTriangle = {kind : "triangle";base : number;height : number };typeRectangle = {kind : "rectangle";width : number;height : number };typeShape =Triangle |Rectangle ;functiongetArea (shape :Shape ): number {// 共通のプロパティkindを利用して型を判定するswitch (shape .kind ) {case "triangle":// この節ではshapeがTriangle型に絞り込まれるreturn (shape .base *shape .height ) / 2;case "rectangle":// この節ではshapeがRectangle型に絞り込まれるreturnshape .width *shape .height ;}}
typescript
typeTriangle = {kind : "triangle";base : number;height : number };typeRectangle = {kind : "rectangle";width : number;height : number };typeShape =Triangle |Rectangle ;functiongetArea (shape :Shape ): number {// 共通のプロパティkindを利用して型を判定するswitch (shape .kind ) {case "triangle":// この節ではshapeがTriangle型に絞り込まれるreturn (shape .base *shape .height ) / 2;case "rectangle":// この節ではshapeがRectangle型に絞り込まれるreturnshape .width *shape .height ;}}
インターセクション型
- インターセクション型は複数の型を1つに結合した新しい型を定義する。
型1 & 型2 & ...
の形式で使う。- その結果として生じた型は、それぞれの型が持つすべてのプロパティとメソッドを備えている。
typescript
typeOctopus = {swims : boolean };typeCat = {nightVision : boolean };typeOctocat =Octopus &Cat ;constoctocat :Octocat = {swims : true,nightVision : true };console .log (octocat );
typescript
typeOctopus = {swims : boolean };typeCat = {nightVision : boolean };typeOctocat =Octopus &Cat ;constoctocat :Octocat = {swims : true,nightVision : true };console .log (octocat );
分割代入
- 分割代入を使うと、配列の各要素を一度に変数に代入できる(配列の分割代入)。
typescript
const [a ,b ] = [1, 2];console .log (a );console .log (b );
typescript
const [a ,b ] = [1, 2];console .log (a );console .log (b );
- 分割代入により、オブジェクトのプロパティを個別の変数へ代入できる(オブジェクトの分割代入)。
typescript
constobj = {name : "John",age : 20,};const {name ,age } =obj ;console .log (name );console .log (age );
typescript
constobj = {name : "John",age : 20,};const {name ,age } =obj ;console .log (name );console .log (age );
条件分岐
- TypeScriptではJavaScriptと同様に、条件分岐には
if
構文やswitch
構文が利用できる。
if-else文
typescript
constage : number = 20;if (age >= 20) {console .log ("You are an adult.");} else {console .log ("You are a minor.");}
typescript
constage : number = 20;if (age >= 20) {console .log ("You are an adult.");} else {console .log ("You are a minor.");}
switch文
typescript
constcolor : string = "blue";switch (color ) {case "red":console .log ("Color is red.");break;case "blue":console .log ("Color is blue.");break;default:console .log ("Color is neither red nor blue.");}
typescript
constcolor : string = "blue";switch (color ) {case "red":console .log ("Color is red.");break;case "blue":console .log ("Color is blue.");break;default:console .log ("Color is neither red nor blue.");}
型の絞り込み
- 条件分岐を利用すると、その節内では型が自動的に絞り込まれる(制御フロー分析と型ガードによる型の絞り込み)。
typescript
letvalue : string | number;// 50%の確率でstring型またはnumber型の値を代入するvalue =Math .random () < 0.5 ? "Hello" : 100;if (typeofvalue === "string") {// この節ではvalueはstring型として扱われるconsole .log (value .toUpperCase ());} else {// この節ではvalueはnumber型として扱われるconsole .log (value * 3);}
typescript
letvalue : string | number;// 50%の確率でstring型またはnumber型の値を代入するvalue =Math .random () < 0.5 ? "Hello" : 100;if (typeofvalue === "string") {// この節ではvalueはstring型として扱われるconsole .log (value .toUpperCase ());} else {// この節ではvalueはnumber型として扱われるconsole .log (value * 3);}
関数
- TypeScriptではアロー関数や関数宣言に型注釈をつけることができる。
アロー関数
typescript
constgreet = (name : string): string => {return `Hello ${name }`;};console .log (greet ("John"));
typescript
constgreet = (name : string): string => {return `Hello ${name }`;};console .log (greet ("John"));
関数宣言
typescript
functiongreet (name : string): string {return `Hello ${name }`;}console .log (greet ("John"));
typescript
functiongreet (name : string): string {return `Hello ${name }`;}console .log (greet ("John"));
分割代入引数
- 関数の引数に配列またはオブジェクトリテラルを展開することができる(分割代入引数)。
typescript
constprintCoord = ({x ,y }: {x : number;y : number }) => {console .log (`Coordinate is (${x }, ${y })`);};printCoord ({x : 10,y : 20 });
typescript
constprintCoord = ({x ,y }: {x : number;y : number }) => {console .log (`Coordinate is (${x }, ${y })`);};printCoord ({x : 10,y : 20 });
型ガード関数
- 特定の型であることを判定する関数(型ガード関数)を利用することで、型が絞り込まれる。
typescript
functionisString (value : any):value is string {return typeofvalue === "string";}functionprintLength (value : any) {if (isString (value )) {// この節ではvalueはstring型として扱われるconsole .log (value .length );}}printLength ("hello");
typescript
functionisString (value : any):value is string {return typeofvalue === "string";}functionprintLength (value : any) {if (isString (value )) {// この節ではvalueはstring型として扱われるconsole .log (value .length );}}printLength ("hello");
オプション引数
- 関数の引数には
?
をつけることで任意とすることができる(オプション引数)。
typescript
functiongreet (name ?: string) {if (name ===undefined ) {return "Hello!";} else {return `Hello ${name }!`;}}console .log (greet ("John"));console .log (greet ());
typescript
functiongreet (name ?: string) {if (name ===undefined ) {return "Hello!";} else {return `Hello ${name }!`;}}console .log (greet ("John"));console .log (greet ());
デフォルト引数
- 関数の引数には
=
を使ってデフォルトの値を設定することができる(デフォルト引数)。
typescript
functiongreet (name : string = "Mystery") {return `Hello ${name }!`;}console .log (greet ("John"));console .log (greet ());
typescript
functiongreet (name : string = "Mystery") {return `Hello ${name }!`;}console .log (greet ("John"));console .log (greet ());
残余引数
...
を使って残余引数(任意の数の引数)を設定することができる。
typescript
functionsum (...numbers : number[]) {returnnumbers .reduce ((total ,num ) =>total +num , 0);}console .log (sum (1, 2, 3, 4, 5));
typescript
functionsum (...numbers : number[]) {returnnumbers .reduce ((total ,num ) =>total +num , 0);}console .log (sum (1, 2, 3, 4, 5));
クラス
クラス構文
typescript
classPerson {name : string;age : number;constructor(name : string,age : number) {this.name =name ;this.age =age ;}introduce (): void {console .log (`My name is ${this.name } and I am ${this.age } years old.`);}}constjohn = newPerson ("John", 20);john .introduce ();
typescript
classPerson {name : string;age : number;constructor(name : string,age : number) {this.name =name ;this.age =age ;}introduce (): void {console .log (`My name is ${this.name } and I am ${this.age } years old.`);}}constjohn = newPerson ("John", 20);john .introduce ();
アクセス修飾子
public
(デフォルト)、protected
、private
の3つのアクセス修飾子が利用できる。
typescript
classPerson {publicname : string;privateage : number;constructor(name : string,age : number) {this.name =name ;this.age =age ;}introduce (): void {console .log (`My name is ${this.name } and I am ${this.age } years old.`);}}constjohn = newPerson ("John", 20);console .log (john .name ); // 'John'が出力されるProperty 'age' is private and only accessible within class 'Person'.2341Property 'age' is private and only accessible within class 'Person'.console .log (john .); // エラー(privateなのでアクセスできない) age
typescript
classPerson {publicname : string;privateage : number;constructor(name : string,age : number) {this.name =name ;this.age =age ;}introduce (): void {console .log (`My name is ${this.name } and I am ${this.age } years old.`);}}constjohn = newPerson ("John", 20);console .log (john .name ); // 'John'が出力されるProperty 'age' is private and only accessible within class 'Person'.2341Property 'age' is private and only accessible within class 'Person'.console .log (john .); // エラー(privateなのでアクセスできない) age
クラスのreadonly修飾子
readonly
修飾子をつけたプロパティは、読み取り専用となる。readonly
修飾子はアクセス修飾子と併用可能。
typescript
classPerson {readonlyname : string;private readonlyage : number;constructor(name : string,age : number) {this.name =name ;this.age =age ;}introduce (): void {console .log (`My name is ${this.name } and I am ${this.age } years old.`);}}constjohn = newPerson ("John", 20);Cannot assign to 'name' because it is a read-only property.2540Cannot assign to 'name' because it is a read-only property.john .= "Tom"; // エラー(readonlyのため変更不可) name
typescript
classPerson {readonlyname : string;private readonlyage : number;constructor(name : string,age : number) {this.name =name ;this.age =age ;}introduce (): void {console .log (`My name is ${this.name } and I am ${this.age } years old.`);}}constjohn = newPerson ("John", 20);Cannot assign to 'name' because it is a read-only property.2540Cannot assign to 'name' because it is a read-only property.john .= "Tom"; // エラー(readonlyのため変更不可) name
Constructor shorthand
- TypeScriptでは、コンストラクタパラメータにアクセス修飾子をつけることで、自動的にそのフィールドが定義される(constructor shorthand)。
- これによりコードの簡略化が図れる。
typescript
classPerson {constructor(publicname : string, privateage : number) {}introduce (): void {console .log (`My name is ${this.name } and I am ${this.age } years old.`);}}constjohn = newPerson ("John", 20);john .introduce ();
typescript
classPerson {constructor(publicname : string, privateage : number) {}introduce (): void {console .log (`My name is ${this.name } and I am ${this.age } years old.`);}}constjohn = newPerson ("John", 20);john .introduce ();
フィールドの初期化子
- フィールド宣言の際に直接初期値を設定できる(フィールドの初期化子)。
typescript
classCounter {count = 0; // 初期値を0に設定// ^^^初期化子increment (): void {this.count ++;}}constcounter = newCounter ();console .log (counter .count );counter .increment ();console .log (counter .count );
typescript
classCounter {count = 0; // 初期値を0に設定// ^^^初期化子increment (): void {this.count ++;}}constcounter = newCounter ();console .log (counter .count );counter .increment ();console .log (counter .count );
静的フィールドと静的メソッド
typescript
classMyClass {staticx = 0;staticprintX (): void {console .log (MyClass .x );}}MyClass .printX ();
typescript
classMyClass {staticx = 0;staticprintX (): void {console .log (MyClass .x );}}MyClass .printX ();
this型
- メソッド内で
this
を返すことで、メソッドの呼び出しを直列につなげるメソッドチェーンを可能にする(メソッドチェーン)。
typescript
classMyClass {value = 1;increment (): this {this.value ++;return this;}add (v : number): this {this.value +=v ;return this;}console .log (this.value );return this;}}newMyClass ().increment ().add (3).
typescript
classMyClass {value = 1;increment (): this {this.value ++;return this;}add (v : number): this {this.value +=v ;return this;}console .log (this.value );return this;}}newMyClass ().increment ().add (3).
クラスの継承
extends
キーワードにより、クラスの継承が可能。- スーパークラスのプロパティ・メソッドの値は、サブクラスからアクセス可能。
typescript
classAnimal {name : string;constructor(name : string) {this.name =name ;}greet (): string {return `Hello, my name is ${this.name }`;}}classDog extendsAnimal {bark (): string {return "Woof!";}}constdog = newDog ("Max");console .log (dog .greet ());console .log (dog .bark ());
typescript
classAnimal {name : string;constructor(name : string) {this.name =name ;}greet (): string {return `Hello, my name is ${this.name }`;}}classDog extendsAnimal {bark (): string {return "Woof!";}}constdog = newDog ("Max");console .log (dog .greet ());console .log (dog .bark ());
instanceof
演算子
instanceof
演算子は、オブジェクトが特定のクラスのインスタンスであるかを判定できる。
typescript
classAnimal {}classDog extendsAnimal {}constdog = newDog ();console .log (dog instanceofDog );console .log (dog instanceofAnimal );
typescript
classAnimal {}classDog extendsAnimal {}constdog = newDog ();console .log (dog instanceofDog );console .log (dog instanceofAnimal );
抽象クラス
abstract
キーワードにより、抽象クラスを定義できる。- 抽象クラスはインスタンス化できず、他のクラスが継承するための基底クラスに使用される。
typescript
abstract classAnimal {abstractmakeSound (): void;move (): void {console .log ("roaming the earth...");}}classDog extendsAnimal {makeSound (): void {console .log ("Woof Woof");}}constdog = newDog ();dog .move ();dog .makeSound ();
typescript
abstract classAnimal {abstractmakeSound (): void;move (): void {console .log ("roaming the earth...");}}classDog extendsAnimal {makeSound (): void {console .log ("Woof Woof");}}constdog = newDog ();dog .move ();dog .makeSound ();
ゲッターとセッター
- ゲッターやセッターは、オブジェクトのプロパティを取得・設定するためのメソッド。
- ゲッターは
get
キーワードで、セッターはset
キーワードで定義する。
typescript
classCircle {private_radius : number;constructor(radius : number) {this._radius =radius ;}// ゲッターgetradius (): number {return this._radius ;}// セッターsetradius (radius : number) {if (radius <= 0) {throw newError ("Invalid radius value");}this._radius =radius ;}}constcircle = newCircle (5);console .log (circle .radius );circle .radius = 3;console .log (circle .radius );circle .radius = -2;// 例外: 'Invalid radius value'
typescript
classCircle {private_radius : number;constructor(radius : number) {this._radius =radius ;}// ゲッターgetradius (): number {return this._radius ;}// セッターsetradius (radius : number) {if (radius <= 0) {throw newError ("Invalid radius value");}this._radius =radius ;}}constcircle = newCircle (5);console .log (circle .radius );circle .radius = 3;console .log (circle .radius );circle .radius = -2;// 例外: 'Invalid radius value'
インターフェース
- TypeScriptのインターフェースは、プロパティ、メソッド、クラスなどの形状を定義する能力を持つ。
- インターフェースを使用する主な目的は、特定のクラスまたはオブジェクトが特定のプロパティまたはメソッドを保持することを強制する。
typescript
interfacePrintable {}classMyClass implementsPrintable {console .log ("Hello, world!");}}
typescript
interfacePrintable {}classMyClass implementsPrintable {console .log ("Hello, world!");}}
インターフェース構文
- TypeScriptのインターフェースはオブジェクトの形状を定義することが可能。
- インターフェースはプロパティやメソッドのシグネチャを記述できる。
typescript
interfacePoint {readonlyx : number;readonlyy : number;sum (): number;}constpoint :Point = {x : 10,y : 20,sum : function () {return this.x + this.y ;},};
typescript
interfacePoint {readonlyx : number;readonlyy : number;sum (): number;}constpoint :Point = {x : 10,y : 20,sum : function () {return this.x + this.y ;},};
インターフェースのreadonly修飾子
- インターフェース内でreadonly修飾子を使用して、プロパティを読み取り専用に設定できる。
- これにより、プロパティの値が一旦設定されると後から変更できなくなる。
typescript
interfacePoint {readonlyx : number;readonlyy : number;}constp1 :Point = {x : 10,y : 20 };Cannot assign to 'x' because it is a read-only property.2540Cannot assign to 'x' because it is a read-only property.p1 .= 5; x
typescript
interfacePoint {readonlyx : number;readonlyy : number;}constp1 :Point = {x : 10,y : 20 };Cannot assign to 'x' because it is a read-only property.2540Cannot assign to 'x' because it is a read-only property.p1 .= 5; x
例外処理
- TypeScriptでは例外処理のためにtry / catch / finally ブロックを使用できる。
- 例外が発生した場合(つまり、エラーオブジェクトをスローした場合)catchブロックが実行される。
typescript
try {throw newError ("An error occurred!");} catch (error ) {console .log (error );}
typescript
try {throw newError ("An error occurred!");} catch (error ) {console .log (error );}
try-catch-finally構文
- tryブロック内のコードは、エラーを検出し、catchブロックはエラーをハンドリングする。
- finallyブロックはエラーの有無に関係なく実行される。
typescript
try {throw newError ("Oops, something went wrong.");} catch (error ) {console .log (error );} finally {console .log ("This is the finally block. It always gets executed.");}
typescript
try {throw newError ("Oops, something went wrong.");} catch (error ) {console .log (error );} finally {console .log ("This is the finally block. It always gets executed.");}
例外クラス
- TypeScriptでは、カスタムエラークラスを作成することも可能。
- Errorクラスを継承したカスタムクラスで、具体的なエラータイプを作成することができる。
typescript
classCustomError extendsError {code = "CustomError";constructor(message ?: string) {super(message );}}try {throw newCustomError ("This is a custom error");} catch (error ) {if (error instanceofCustomError ) {console .log (`${error .code }: ${error .message }`);}}
typescript
classCustomError extendsError {code = "CustomError";constructor(message ?: string) {super(message );}}try {throw newCustomError ("This is a custom error");} catch (error ) {if (error instanceofCustomError ) {console .log (`${error .code }: ${error .message }`);}}
非同期処理
- TypeScriptでは、非同期プログラミングをサポートしていて、コード内で時間を要する処理を効率的に扱うことができる。
Promise
- Promiseは非同期操作の最終的な完了(または失敗)とその結果の値を表す。
typescript
constpromise = newPromise ((resolve ,reject ) => {setTimeout (() => {resolve ("Promise resolved");}, 2000);});promise .then ((data ) => {console .log (data );});
typescript
constpromise = newPromise ((resolve ,reject ) => {setTimeout (() => {resolve ("Promise resolved");}, 2000);});promise .then ((data ) => {console .log (data );});
async/await 構文
typescript
functiondelay (ms : number) {return newPromise ((resolve ) =>setTimeout (resolve ,ms ));}async functionasyncFunction () {console .log ("Start");awaitdelay (2000);console .log ("End");}asyncFunction ();// 2秒後
typescript
functiondelay (ms : number) {return newPromise ((resolve ) =>setTimeout (resolve ,ms ));}async functionasyncFunction () {console .log ("Start");awaitdelay (2000);console .log ("End");}asyncFunction ();// 2秒後
ジェネリクス
typescript
// Tが型変数functionidentity <T >(arg :T ):T {returnarg ;}// 型変数Tにstringを割り当てるconstoutput1 =identity <string>("myString");// 型変数Tにnumberを割り当てるconstoutput2 =identity <number>(100);
typescript
// Tが型変数functionidentity <T >(arg :T ):T {returnarg ;}// 型変数Tにstringを割り当てるconstoutput1 =identity <string>("myString");// 型変数Tにnumberを割り当てるconstoutput2 =identity <number>(100);
モジュール
- TypeScriptのモジュールシステムは、他のモジュールと共有するコードと、モジュール内部限定のコードとを分けることを可能にする(モジュール)。
greeter.tstypescript
export functiongreet (name : string) {return `Hello, ${name }!`;}
greeter.tstypescript
export functiongreet (name : string) {return `Hello, ${name }!`;}
main.tstypescript
import {greet } from "./greeter";console .log (greet ("TypeScript"));
main.tstypescript
import {greet } from "./greeter";console .log (greet ("TypeScript"));
importとexport
- モジュール内で定義した関数や変数を外部に公開するには、exportを使用する。
- モジュールが公開した関数や変数を利用するには、importを使用する。
math.tstypescript
export functionsquare (x : number) {returnx *x ;}export functioncube (x : number) {returnx *x *x ;}
math.tstypescript
export functionsquare (x : number) {returnx *x ;}export functioncube (x : number) {returnx *x *x ;}
main.tstypescript
import {square ,cube } from "./math";console .log (square (2));console .log (cube (2));
main.tstypescript
import {square ,cube } from "./math";console .log (square (2));console .log (cube (2));
default export
- defaultキーワードを使用すると、モジュールがデフォルトで1つの値のみをエクスポートすることを意味する。
- default exportは、importする際に別名を指定することが可能である。
greeter.tstypescript
export default functiongreet (name : string) {return `Hello, ${name }!`;}
greeter.tstypescript
export default functiongreet (name : string) {return `Hello, ${name }!`;}
main.tstypescript
importgreetFunction from "./greeter";console .log (greetFunction ("TypeScript"));
main.tstypescript
importgreetFunction from "./greeter";console .log (greetFunction ("TypeScript"));
再export
- モジュールは、別のモジュールからエクスポートされたものを再エクスポートすることができる。
math.tstypescript
export functionadd (x : number,y : number) {returnx +y ;}
math.tstypescript
export functionadd (x : number,y : number) {returnx +y ;}
index.tstypescript
// 再エクスポートexport {add } from "./math";
index.tstypescript
// 再エクスポートexport {add } from "./math";
main.tstypescript
import {add } from "./index";console .log (add (2, 3));
main.tstypescript
import {add } from "./index";console .log (add (2, 3));
type importとtype export
- 型だけをエクスポート・インポートすることもできる。
types.tstypescript
export typeMyObject = {name : string;age : number;};
types.tstypescript
export typeMyObject = {name : string;age : number;};
main.tstypescript
import type {MyObject } from "./types";// ^^^^型インポートconstobj :MyObject = {name : "TypeScript",age : 3,};
main.tstypescript
import type {MyObject } from "./types";// ^^^^型インポートconstobj :MyObject = {name : "TypeScript",age : 3,};
型レベルプログラミング
- TypeScriptには、typeof演算子やkeyof演算子、ユーティリティータイプなど、型レベルでプログラミングをするためのさまざまな機能が搭載されている。
typeof型演算子
- typeof演算子は、変数名から型を逆算できる。
typescript
constobject = {name : "TypeScript",version : 3.9,};typeObjectType = typeofobject ;
typescript
constobject = {name : "TypeScript",version : 3.9,};typeObjectType = typeofobject ;
keyof型演算子
- keyof演算子を使うと、object型のすべてのキーを文字列リテラルのユニオン型として取得できる。
typescript
typePoint = {x : number;y : number;};typeKey = keyofPoint ;constkey1 :Key = "x"; // 代入OKconstkey2 :Key = "y"; // 代入OKconstType '"z"' is not assignable to type 'keyof Point'.2322Type '"z"' is not assignable to type 'keyof Point'.: key3 Key = "z"; // 代入不可
typescript
typePoint = {x : number;y : number;};typeKey = keyofPoint ;constkey1 :Key = "x"; // 代入OKconstkey2 :Key = "y"; // 代入OKconstType '"z"' is not assignable to type 'keyof Point'.2322Type '"z"' is not assignable to type 'keyof Point'.: key3 Key = "z"; // 代入不可
type Key = keyof Point = "x" | "y"
となる。
ユーティリティ型
- TypeScriptは、既存の型から新しい型を作成するためのさまざまな一般的な型操作を提供している。
Required
Required
は、オプションプロパティを必須プロパティにするユーティリティ型。
typescript
typePerson = {name : string;age ?: number;};typeRequiredPerson =Required <Person >;// ageがオプションでなくなっている点に注目
typescript
typePerson = {name : string;age ?: number;};typeRequiredPerson =Required <Person >;// ageがオプションでなくなっている点に注目
Partial
Partial
は、型のすべてのプロパティをオプションにするユーティリティ型。
typescript
typePerson = {name : string;age : number;};typeOptionalPerson =Partial <Person >;
typescript
typePerson = {name : string;age : number;};typeOptionalPerson =Partial <Person >;
Readonly
Readonly
は、型のすべてのプロパティをreadonlyにするユーティリティ型。それらのプロパティは再代入できない。
typescript
typePerson = {name : string;age : number;};typeReadonlyPerson =Readonly <Person >;
typescript
typePerson = {name : string;age : number;};typeReadonlyPerson =Readonly <Person >;
Record
Record
は、オブジェクトのすべてのプロパティ値を特定の型に設定するユーティリティ型。
typescript
typeThreeLetterRecord =Record <"one" | "two" | "three", string>;
typescript
typeThreeLetterRecord =Record <"one" | "two" | "three", string>;
Pick
Pick
は、オブジェクトから特定のプロパティだけを拾い出すユーティリティ型。
typescript
typePerson = {name : string;age : number;address : string;};typePersonNameAndAge =Pick <Person , "name" | "age">;
typescript
typePerson = {name : string;age : number;address : string;};typePersonNameAndAge =Pick <Person , "name" | "age">;
Omit
Omit
は、オブジェクトから特定のプロパティを省いた型を作るユーティリティ型。
typescript
typePerson = {name : string;age : number;address : string;};typePersonWithoutAddress =Omit <Person , "address">;
typescript
typePerson = {name : string;age : number;address : string;};typePersonWithoutAddress =Omit <Person , "address">;
Exclude
Exclude
は、ユニオン型から特定の型を除外するユーティリティ型。
typescript
typeT1 = number | string | boolean;typeT2 =Exclude <T1 , boolean>;
typescript
typeT1 = number | string | boolean;typeT2 =Exclude <T1 , boolean>;
Extract
Extract
は、ふたつのユニオン型の共通の部分を抽出するユーティリティ型。
typescript
typeT1 = number | string | boolean;typeT2 = string | boolean;typeT3 =Extract <T1 ,T2 >;
typescript
typeT1 = number | string | boolean;typeT2 = string | boolean;typeT3 =Extract <T1 ,T2 >;
NonNullable
NonNullable
は、nullまたはundefinedを含む型からいずれも除外するユーティリティ型。
typescript
typeT1 = string | null | undefined;typeT2 =NonNullable <T1 >;
typescript
typeT1 = string | null | undefined;typeT2 =NonNullable <T1 >;
ReturnType
ReturnType
は、関数の戻り値の型を取得するユーティリティ型。
typescript
functionstringify (value : number): string {return `${value }`;}typeStringifyReturnType =ReturnType <typeofstringify >;
typescript
functionstringify (value : number): string {return `${value }`;}typeStringifyReturnType =ReturnType <typeofstringify >;
Awaited
Awaited
は、Promiseの戻り値の型を取得するユーティリティ型。
typescript
constpromise1 =Promise .resolve ("data");constpromise2 =Promise .resolve (Promise .resolve ("data"));typeData1 =Awaited <typeofpromise1 >;typeData2 =Awaited <typeofpromise2 >;
typescript
constpromise1 =Promise .resolve ("data");constpromise2 =Promise .resolve (Promise .resolve ("data"));typeData1 =Awaited <typeofpromise1 >;typeData2 =Awaited <typeofpromise2 >;
Mapped types
- Mapped typesを使うと、既存の型から新しい型を生成できる。
- Mapped typesは、オブジェクトの各プロパティを”マップ”し、新しいオブジェクトを生成する。
typescript
typePerson = {name : string;age : number;};typeReadOnlyPerson = { readonly [K in keyofPerson ]:Person [K ] };
typescript
typePerson = {name : string;age : number;};typeReadOnlyPerson = { readonly [K in keyofPerson ]:Person [K ] };
インデックスアクセス型
- インデックスアクセス型を使うと、型のプロパティの型を取得できる。
typescript
typePerson = {name : string;age : number;};typeName =Person ["name"];
typescript
typePerson = {name : string;age : number;};typeName =Person ["name"];