TypeScript
メインページ > 工学 > 情報技術 > プログラミング > TypeScript
TypeScriptは、JavaScriptのスーパーセットです。TypeScriptは、静的型付け、クラス、インターフェース、継承などの機能をJavaScriptに加えます。 これにより、開発者はより大規模なプロジェクトでの開発をより効率的に行うことができます。 本チュートリアルでは、TypeScriptの基本的な構文、データ型、関数、クラス、インターフェースなどについて学習できます。
TypeScriptの概要[編集]
TypeScriptの概要[編集]
TypeScriptは、マイクロソフトによって開発された、JavaScriptのスーパーセット言語であり、JavaScriptに対して型システムやクラス、インターフェイス、ジェネリクスなどの静的な機能を追加しています。TypeScriptは、JavaScriptの開発をより安全かつ効率的にするために設計されています。
TypeScriptの特徴[編集]
TypeScriptの主な特徴は以下の通りです。
- 静的型付け:変数や関数の型を宣言し、コンパイル時に型のチェックを行うことができます。
- クラスやインターフェイスのサポート:オブジェクト指向プログラミングをサポートし、コードの再利用性や保守性を高めることができます。
- コンパイル時のエラーチェック:コンパイル時にエラーチェックを行うことで、ランタイムエラーを事前に防止することができます。
- ES6/ES2015以降の構文のサポート:TypeScriptはES6/ES2015以降の構文をサポートしており、コードをより簡潔かつ読みやすくすることができます。
JavaScriptとの違い[編集]
JavaScriptは動的型付けの言語であり、変数の型を宣言する必要がありません。一方、TypeScriptは静的型付けの言語であり、変数や関数の型を宣言することができます。
JavaScriptはオブジェクト指向プログラミングをサポートしていますが、クラスやインターフェイスの宣言方法は限定的です。一方、TypeScriptはオブジェクト指向プログラミングをより豊富にサポートしており、クラスやインターフェイスの宣言がより柔軟になっています。
JavaScriptはコンパイルエラーを実行時に発生させるため、開発者がエラーを特定するのが難しい場合があります。一方、TypeScriptはコンパイル時にエラーチェックを行うため、開発者は実行時にエラーが発生することを事前に防止することができます。
TypeScriptのインストール[編集]
以下は、Node.js、Deno、およびTypeScript PlaygroundでTypeScriptをインストールおよびビルドする方法です。
- Node.js
-
- Node.jsをインストールします。
- ターミナルで、
npm install -g typescript
を実行して、TypeScriptをグローバルにインストールします。 tsc
コマンドを実行して、TypeScriptをコンパイルします。
- Deno
-
- Denoをインストールします。
- ターミナルで、
deno install -n ts https://deno.land/std/typescript/tsc.ts
を実行して、TypeScriptコンパイラをインストールします。 - TypeScriptファイルを作成し、
ts
コマンドを使用してコンパイルします。例:ts file.ts
- TypeScript Playground
-
- TypeScript Playgroundにアクセスします( https://www.typescriptlang.org/play )。
- 左側のペインにTypeScriptコードを入力します。
- 右側のペインには、JavaScriptにコンパイルされたコードが表示されます。また、コンパイルエラーがある場合は、そのエラーが表示されます。
それぞれの特徴:
- Node.js
- Node.jsは、JavaScriptを使用してサーバーサイドアプリケーションを開発するためのオープンソースのランタイム環境です。Node.jsは、GoogleのV8 JavaScriptエンジンをベースに構築されており、非同期I/O処理、イベント駆動アーキテクチャ、モジュールベースのアプローチなどの特徴を持っています。
- Node.jsは、特にWebアプリケーションの開発に適しています。サーバーサイドのJavaScriptを実行することで、クライアント側とサーバー側のコードを同じ言語で書くことができます。また、Node.jsは、多くのパッケージやライブラリが用意されており、開発の効率性が高くなっています。
- Node.jsは、フロントエンドのJavaScriptフレームワークとの組み合わせによって、フルスタックのWebアプリケーションを開発することができます。特に、ReactやAngularといった人気のあるフレームワークとの組み合わせが多く使われています。
- Node.jsは、多くの企業や開発者によって採用されており、高い人気を誇っています。また、Node.jsはオープンソースのプロジェクトであり、コミュニティによって開発が進められています。
- Deno
- Denoは、JavaScriptやTypeScriptを使用してサーバーサイドアプリケーションを開発するためのランタイム環境であり、Node.jsと同様にオープンソースであります。
- Denoは、Node.jsと同様に、GoogleのV8 JavaScriptエンジンをベースに構築されていますが、Node.jsとは異なり、Denoは非同期I/O処理とイベント駆動アーキテクチャを強調する代わりに、よりシンプルで安全なAPIを提供しています。
- Denoは、Node.jsと比較して、よりセキュアなデフォルト設定を持っており、外部の依存関係を管理するためのパッケージマネージャーが組み込まれています。また、DenoはTypeScriptのサポートに優れており、標準でTypeScriptをサポートしています。
- Denoは、Node.jsとは異なるアーキテクチャとAPIを提供するため、開発者は学習コストを負担する必要がありますが、Denoは、セキュリティや依存関係管理の面で優れた機能を提供するため、特にセキュリティ上の懸念がある企業やプロジェクトに適しているとされています。
- TypeScript Playground( https://www.typescriptlang.org/play )
- TypeScript Playgroundは、ブラウザ上でTypeScriptのコードを書いて、そのコードをコンパイルし、実行結果を確認するためのオンラインツールです。
- Playgroundは、TypeScriptを学ぶための最適な方法の1つであり、JavaScript開発者がTypeScriptの構文、型、および機能を探索することができます。また、TypeScriptのコードを試して、実行前にコードがどのように動作するかを確認することもできます。
- Playgroundの左側には、TypeScriptコードを入力するためのエディターがあります。また、エディター内でコードを書いた後、右側にJavaScriptコードのプレビューが表示されます。Playgroundは、TypeScriptファイルを読み込むこともでき、ファイルをアップロードしてプレビューを確認することができます。
- Playgroundは、TypeScriptの基礎を学ぶために非常に役立つツールであり、TypeScriptの導入前に、実際にコードを書いて、コンパイル結果を確認することができます。
トランスパイラ |
トランスパイラは、一種のコンパイラの一つで、あるプログラムのソースコードを別の言語のソースコードに変換するものです。例えば、JavaScriptのコードをTypeScriptのコードに変換するトランスパイラや、PythonのコードをC言語のコードに変換するトランスパイラなどがあります。トランスパイラは、プログラムの言語のバージョン管理や最適化、移植性向上などの目的で使用されます。 |
TypeScriptのコードの直接実行[編集]
ts-nodeは、Node.jsのランタイム環境でTypeScriptコードを実行するためのツールです。Node.jsは、JavaScriptを実行するためのランタイム環境であるため、TypeScriptのコードを直接実行することはできませんが、ts-nodeを使用することで、TypeScriptのコードをトランスパイルせずに直接実行することができます。
ts-nodeは、TypeScriptの実行を容易にするために開発され、TypeScriptファイルをコンパイルし、実行する必要がないため、より速く開発することができます。また、TypeScriptの実行に必要な設定ファイルや依存関係の管理も自動的に行われます。
ts-nodeは、グローバルにインストールすることができ、コマンドラインから単一のファイルまたはディレクトリを実行することができます。また、ts-nodeは、Node.js REPL(Read-Eval-Print Loop)にも統合されており、TypeScriptのスニペットをインタラクティブに実行することができます。
% npx ts-node ファイル名.ts
だけでコンパイルと実行が行われ、ソースコードが変更されていない場合は、キャッシュ上のコンパイル後の .js を直接実行します。
ts-nodeは、TypeScriptプロジェクトの開発をより迅速かつ簡単にするための便利なツールであり、特にNode.jsとTypeScriptを組み合わせた開発において、大きな利点を提供します。
TypeScriptの基本文法[編集]
// 変数と定数 let num: number = 123; // 数値型の変数 const str: string = "Hello TypeScript!"; // 文字列型の定数 var flag: boolean = true; // 真偽値型の変数 // 型の宣言 type User = { name: string; age: number; } const user: User = { name: "Alice", age: 20 }; // User型のオブジェクト // 関数とクラス function greet(name: string): void { console.log(`Hello, ${name}!`); } class Animal { name: string; constructor(name: string) { this.name = name; } sayHello(): void { console.log(`Hello, I'm ${this.name}.`); } } const cat: Animal = new Animal("Tama"); // Animalクラスのインスタンス cat.sayHello(); // インターフェイスとジェネリックス interface Person<T> { name: string; age: T; } const person: Person<number> = { name: "Bob", age: 25 }; // Person型のオブジェクト // 制御構文 /// 分岐 if (flag) { console.log("This is true."); } else { console.log("This is false."); } switch (num) { case 0: console.log("zero"); break; case 1: console.log("one"); break; default: console.log("other"); break; } /// 繰り返し for (let i = 0; i < num; i++) { console.log(i); } let i = 0; while (i < num) { console.log(i); i++; }
このコードの中で、TypeScriptとJavaScriptの主な違いは変数、定数、関数、クラス、インターフェース、ジェネリックス、および制御構文の宣言に型情報を含んでいることです。
具体的には、変数の宣言には型アノテーションが含まれています。JavaScriptでは、変数の宣言時に型を指定する必要はありません。
また、型の宣言にはTypeScriptで導入されたtypeキーワードが使用されており、JavaScriptには存在しません。
関数の引数と返り値に型情報が含まれており、関数が返す値の型を指定する必要があります。JavaScriptでは、関数の引数や返り値に型を指定する必要はありません。
クラスのメンバー変数やメソッドにも型情報が含まれており、JavaScriptではクラスのメンバーに型を指定する方法がありません。
インターフェイスにはジェネリック型パラメータが含まれており、TypeScriptにはジェネリック型パラメータをサポートする機能がありますが、JavaScriptには存在しません。
制御構文は、if-else分岐、switch文、forループ、whileループが含まれていますが、JavaScriptとの違いはありません。ただし、ループ内で使用される変数については、TypeScriptでは事前に型を指定する必要があります。
変数と型[編集]
TypeScriptでは、JavaScript の変数宣言に加え、変数名の後に ':' に続けて 型名 を書きます。
- 構文
let 変数名 : 型名 = 初期値 ;
- このように明示的型を指定する仕組みを、型アノテーションと言います。
型 | 説明 |
---|---|
any | 任意の型 |
number | 数値 |
string | 文字列 |
boolean | 真理値 (true/false) |
void | 値を返さない (undefined相当) |
null | null |
undefined | undefined |
never | 発生しない値(例外が発生して関数が抜け出せなくなった場合など) |
unknown | anyと同様任意の型、しかし、型の安全性を保持するための安全なany型 |
object | オブジェクト |
array | 配列 |
tuple | 固定長の配列 |
enum | 列挙型 |
union | 複数の型のいずれか1つを受け入れ可能 |
intersection | 複数の型を結合 |
type | 型エイリアス。型に名前をつけた、再利用可能な定義 |
class | クラス |
interface | オブジェクトの構造や形状を定義 |
function | 関数 |
注意: 上記の型は基本的なものであり、カスタム型を作成することも可能です。
any型[編集]
TypeScriptのany型は、JavaScriptの動的型付けに対して静的型付けを導入するTypeScriptで、JavaScriptの動的型付けに相当する概念です。
JavaScriptでは、変数にどの型の値でも代入できます。これは、JavaScriptが動的型付けを採用しているためです。一方、TypeScriptでは、型安全性を高めるために静的型付けが導入されています。このため、TypeScriptでは、変数には事前に定義された型しか代入できません。しかし、any型を使用することで、TypeScriptの静的型付けシステムを一時的に回避することができます。
any型は、どの型の値でも代入できる型です。JavaScriptと同様に、any型を使用することで、変数にどのような値でも代入できるようになります。これにより、TypeScriptにおいて、動的な型付けを実現することができます。
any型の使用は、型安全性が低下する可能性があるため、推奨されません。any型を使用すると、TypeScriptが提供する静的型付けの恩恵を失うことになります。any型の使用は、コードの可読性や保守性を損なう可能性があるため、最小限に抑えることが重要です。
JavaScriptには、any型に相当する概念はありません。JavaScriptは動的型付けを採用しており、変数にどの型の値でも代入できます。TypeScriptのany型は、JavaScriptにおいては必要のない概念であり、TypeScriptが提供する型安全性の恩恵を受けるために導入された型です。
数値型(number)[編集]
TypeScriptの数値型は、JavaScriptの数値型と同様に、64ビットの浮動小数点数として実装されています。しかし、TypeScriptにはいくつかの追加機能があります。 まず、TypeScriptの数値型には、JavaScriptにはない2進数と8進数のリテラル表記があります。例えば、以下のように2進数と8進数のリテラルを直接代入することができます。
let binary: number = 0b1010; let octal: number = 0o744;
また、TypeScriptには、数値リテラルに対してアンダースコアを挿入して桁区切りを指定することができます。例えば、以下のように数値リテラルを分かりやすく書くことができます。
let bigNumber: number = 1_000_000_000;
さらに、TypeScriptの数値型には、NaN、Infinity、および-Math.Infinityの3つの追加値があります。これらは、JavaScriptのNumber型にも存在しますが、TypeScriptはこれらの値の使用に関して、より厳密な型チェックを提供します。例えば、以下のように、NaNとInfinityの比較を行う場合、TypeScriptはエラーを検出します。
let nanValue: number = NaN; let infinityValue: number = Infinity; console.log(nanValue === infinityValue); // false (TypeScript error)
以上のように、TypeScriptの数値型には、JavaScriptにはないいくつかの追加機能があります。これらの機能は、数値処理をより簡単かつ正確に行うためのものであり、開発者にとって大きな利点を提供します。
TypeScriptのnumberは浮動小数点数型 |
JavaScriptの数値は IEEE 754 の64ビット倍精度浮動小数点数です。
TypeScriptのプログラムは、JavaScriptにトランスパイルされ、JavaScriptエンジンで実行されるので、同じく型numberも64ビット倍精度浮動小数点数です。
実行時に、 どうしても整数に限定した型がほしい場合は、BigInt オブジェクトがあります。
BigInt オブジェクトのリテラルは、 |
文字列型(string)[編集]
TypeScriptの文字列型は、JavaScriptの文字列型と同様に、文字のシーケンスを表すために使用されます。ただし、TypeScriptにはいくつかの追加機能があります。
まず、TypeScriptの文字列型には、バッククォートを使用したテンプレート文字列があります。これは、JavaScriptのバッククォートを使用したテンプレート文字列と似ていますが、TypeScriptでは、テンプレート文字列内に埋め込まれた式の型チェックを行うことができます。以下は、テンプレート文字列内に変数を埋め込んで使用する例です。
let name: string = "John"; let age: number = 30; let message: string = `My name is ${name} and I am ${age} years old.`; console.log(message); // "My name is John and I am 30 years old."
また、TypeScriptには、文字列リテラル型があります。これは、文字列リテラルを使用して型を定義することができる機能であり、文字列リテラル型を使用することで、文字列リテラルの集合に対して安全に操作を行うことができます。以下は、文字列リテラル型を使用して、有効な色名のみを受け付ける関数を定義する例です。
type Color = "red" | "green" | "blue"; function setColor(color: Color) { // ... } setColor("red"); // OK setColor("yellow"); // TypeScript error: Argument of type 'yellow' is not assignable to parameter of type 'Color'.
以上のように、TypeScriptの文字列型には、JavaScriptにはないいくつかの追加機能があります。これらの機能は、文字列処理をより簡単かつ正確に行うためのものであり、開発者にとって大きな利点を提供します。
真理値型(boolean)[編集]
TypeScriptの真理値型(boolean)は、JavaScriptの真理値型と同様に、trueまたはfalseの値を持ちます。
JavaScriptと同様に、TypeScriptの真理値型は、if文や三項演算子などの条件分岐に使用されます。しかし、TypeScriptの真理値型にはいくつかの差異があります。
まず、TypeScriptの真理値型は、明示的な型注釈を使用して変数に型を割り当てる場合に必要です。つまり、TypeScriptで変数に真理値型の値を代入する場合、明示的に型注釈を付ける必要があります。例えば、以下のコードを考えてみましょう。
let isDone: boolean = true;
このコードでは、変数isDoneにtrueという真理値型の値を代入しています。しかし、この代入文で明示的に型注釈を使用していることに注意してください。
また、TypeScriptの真理値型は、JavaScriptの厳密等価演算子(===)や不等価演算子(!==)の使用を推奨します。これは、TypeScriptが型安全性を重視しているためです。厳密等価演算子と不等価演算子は、値と型が一致しない場合にも比較を行うため、型の不一致によるバグを防ぐことができます。例えば、以下のコードを考えてみましょう。
let num: number = 0; let isTrue: boolean = false; if (num === isTrue) { console.log('This should not be executed!'); }
このコードでは、変数numに0という数値型の値を代入し、変数isTrueにfalseという真理値型の値を代入しています。その後、if文でnumとisTrueを比較しています。この比較は、JavaScriptではfalseになりますが、TypeScriptではコンパイルエラーとなります。これは、numとisTrueが型が異なるためです。このように、厳密等価演算子や不等価演算子の使用によって、TypeScriptは型安全性を保つことができます。
JavaScriptにおいても真理値型はありますが、明示的な型注釈の必要はありません。また、厳密等価演算子や不等価演算子の使用は推奨されますが、必須ではありません。JavaScriptは動的型付けを採用しており、このため比較演算子の使用によってバグを回避することはできません。
void[編集]
JavaScriptでは、void
キーワードは式を評価して何も返さないことを示します。たとえば、console.log()
関数は値を返さないため、型アノテーションとしてvoid
を使用することができます。
しかし、TypeScriptではvoid
はやや異なります。TypeScriptのvoid
型は、戻り値がない関数の戻り値の型を指定するために使用されます。具体的には、void
型は何も返さない関数(つまり、return
ステートメントを含まない関数)の戻り値の型を指定するために使用されます。void
型を指定することで、TypeScriptはその関数が値を返さないことを保証します。
例えば、以下のような関数があるとします。
function logMessage(message: string): void { console.log(message); }
この関数は、string
型の引数を受け取り、それをコンソールに出力しますが、何も返しません。そのため、void
型を戻り値の型として指定する必要があります。
一方、JavaScriptでは、void
は戻り値がないことを示すために使用されますが、型システムでは使用されません。JavaScriptでは、値を返さない関数は、単に何も返さないため、void
キーワードは必要ありません。
null[編集]
JavaScriptには、null
という値があります。この値は、変数に何も割り当てることができないことを示します。つまり、変数はnull
以外の値を持つことができますが、null
自体は値を持ちません。
一方、TypeScriptでは、null
型があります。null
型は、変数がnull
値またはundefined
値を持つことを明示的に示すために使用されます。
以下は、null
型の使用例です。
let myString: string | null = "Hello World"; myString = null;
この例では、myString
変数はstring
型またはnull
型を持つことができます。最初に、myString
変数に文字列を割り当て、次にnull
を割り当てることができます。string
型の変数にnull
を直接割り当てることはできません。
このように、TypeScriptのnull
型は、null
またはundefined
値を受け入れる変数の型を定義するために使用されます。JavaScriptでは、null
は値自体を表すために使用されますが、型として使用されることはありません。
undefined[編集]
JavaScriptには、undefined
という値があります。この値は、変数に値が割り当てられていないことを示します。つまり、変数はundefined
以外の値を持つことができますが、undefined
自体は値を持ちません。
一方、TypeScriptでは、undefined
型があります。undefined
型は、変数がundefined
値を持つことを明示的に示すために使用されます。
以下は、undefined
型の使用例です。
let myNumber: number | undefined; console.log(myNumber); // undefined
この例では、myNumber
変数はnumber
型またはundefined
型を持つことができます。変数に何も割り当てられていないため、console.log()
関数で変数の値を出力すると、undefined
が表示されます。
このように、TypeScriptのundefined
型は、変数がundefined
値を持つことを明示的に示すために使用されます。JavaScriptでは、undefined
は値自体を表すために使用されますが、型として使用されることはありません。
never[編集]
JavaScriptには、never
型はありません。しかし、TypeScriptにおいては、never
型は存在します。この型は、関数が終了しないことを示します。
例えば、次のような関数があります。
function throwError(message: string): never { throw new Error(message); }
この関数は、Error
オブジェクトをスローしています。Error
オブジェクトがスローされた場合、関数は終了することはありません。そのため、この関数の戻り値の型はnever
となっています。
また、never
型は、型システムの中でエラーを表すためにも使用されます。例えば、以下のような関数があった場合、
function handleError(): never { while (true) { // エラー処理 } }
この関数は、while
ループ内でエラーを処理するために、無限ループを行います。このため、この関数の戻り値の型はnever
になります。
never
型は、TypeScriptの静的型付けにおいて、関数が終了しないことや、エラーを表すことを明示的に示すために使用されます。JavaScriptでは、never
型は存在しないため、この型を使用することはできません。
unknown[編集]
unknown
型は、TypeScript 3.0から導入された型の一つで、JavaScriptには存在しない型です。この型は、ある値が何であるかを明確にはわからない場合に使用されます。
JavaScriptでは、どんな型の値でも代入可能なのに対し、TypeScriptでは型の厳密さが求められます。そのため、TypeScriptの静的型付けにおいて、未知の型を扱う場合にはunknown
型が用意されています。
unknown
型を使うと、変数の型が未知の場合、型チェックを通過するためには、先に型ガードを行う必要があります。以下は、unknown
型の変数を扱う例です。
let value: unknown = "Hello, TypeScript!"; // 文字列型かどうかを判定する if (typeof value === "string") { // valueはstring型に変更されるため、以下のように文字列メソッドを使用できる console.log(value.toLowerCase()); // "hello, typescript!" }
このように、unknown
型は、変数の型が不明な場合に使用されます。そのため、値に対する型チェックを実施する必要があります。unknown
型を使用することで、JavaScriptにはない型安全性を保つことができます。
object[編集]
object
型は、TypeScriptにおける型の一つで、JavaScriptにも存在する型です。ただし、TypeScriptのobject
型はJavaScriptのobject
型とは異なる点がいくつかあります。
JavaScriptのobject
型は、すべてのオブジェクトを表す汎用的な型であり、配列や関数も含まれます。一方、TypeScriptのobject
型は、非プリミティブ型であり、オブジェクトのプロパティとそのプロパティの型を定義するために使用されます。
以下は、object
型を使用してオブジェクトを定義する例です。
let person: object = { name: "John", age: 30 };
この例では、person
変数にobject
型のオブジェクトを代入しています。この場合、object
型は、オブジェクトのプロパティとそのプロパティの型を定義するために使用されています。
一方、JavaScriptでは、object
型は汎用的な型であるため、オブジェクトのプロパティやその型を指定することはできません。また、JavaScriptには型注釈がないため、変数の型を指定することもできません。
let person = { name: "John", age: 30 };
このように、TypeScriptのobject
型は、JavaScriptのobject
型とは異なる点があるため、注意が必要です。
array[編集]
TypeScriptの配列型は、JavaScriptの配列型と非常に似ていますが、いくつかの追加機能があります。
まず、TypeScriptの配列型には、要素の型を指定することができます。これは、JavaScriptの配列型にはない機能であり、配列内の要素の型が一致しない場合に、TypeScriptは型エラーを発生させます。以下は、number型の配列を定義する例です。
let numbers: number[] = [1, 2, 3];
また、TypeScriptの配列型には、ジェネリック型を使用して、任意の型の配列を表現することができます。以下は、ジェネリック型を使用して、文字列型の配列を定義する例です。
let names: Array<string> = ["John", "Jane", "Bob"];
さらに、TypeScriptの配列型には、読み取り専用の配列型があります。これは、配列の要素を変更できないことを保証する型であり、TypeScriptは、読み取り専用の配列型を使用して、配列を操作する関数やメソッドが要素を変更しないことを確認します。以下は、読み取り専用の配列型を使用して、配列の要素を変更できないことを保証する例です。
let numbers: readonly number[] = [1, 2, 3]; numbers[0] = 4; // TypeScript error: Index signature in type 'readonly number[]' only permits reading.
以上のように、TypeScriptの配列型には、JavaScriptにはないいくつかの追加機能があります。これらの機能は、配列操作をより安全かつ正確に行うためのものであり、開発者にとって大きな利点を提供します。
tuple[編集]
tuple
は、TypeScriptにおける型の一つで、複数の要素を含む配列を表すために使用されます。JavaScriptにはtuple
型は存在しないため、TypeScriptとJavaScriptとの間には差異があります。
以下は、tuple
を使用して数値と文字列を持つ配列を定義する例です。
let myTuple: [number, string] = [1, "hello"];
この例では、myTuple
変数に[number, string]
型の配列を代入しています。[number, string]
型は、最初の要素が数値型、2番目の要素が文字列型であることを定義しています。
let myArray = [1, "hello"];
一方、JavaScriptでは、配列の要素には制限がありません。任意の型の要素を持つことができます。
このように、TypeScriptのtuple
型は、JavaScriptの配列とは異なる点があります。TypeScriptのtuple
型は、要素の数と型が固定されており、型安全性を高めることができます。
enum[編集]
enum
は、TypeScriptにおける型の一つで、列挙型を表現するために使用されます。JavaScriptにはenum
型は存在しないため、TypeScriptとJavaScriptとの間には差異があります。
以下は、enum
を使用して曜日を表す列挙型を定義する例です。
enum DayOfWeek { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }
この例では、DayOfWeek
という名前の列挙型を定義しています。enum
キーワードを使用し、{}
の中に列挙する値を記述しています。ここでは、Sunday
からSaturday
までの曜日を定義しています。
一方、JavaScriptでは、列挙型を表現する方法はありません。通常は、定数を使用することで同様の機能を実現します。
const DayOfWeek = { Sunday: 0, Monday: 1, Tuesday: 2, Wednesday: 3, Thursday: 4, Friday: 5, Saturday: 6 };
このように、TypeScriptのenum
型は、JavaScriptの定数とは異なる点があります。TypeScriptのenum
型は、列挙型を表現するために特別に設計されており、列挙型の使用をより簡単に、かつ型安全に実現することができます。
union[編集]
Union型はTypeScriptが提供する型のひとつで、複数の型をひとつの変数に代入することができます。JSにはUnion型は存在しません。
例えば、以下のようなUnion型の宣言ができます。
let value: string | number;
上記の例では、value
はstring
またはnumber
のどちらかの型であることが宣言されています。これにより、文字列や数値をvalue
に代入することができます。
value = "hello"; value = 123;
また、Union型は|
演算子を使用することで、任意の型を複数組み合わせることができます。例えば、以下のような宣言ができます。
let status: "success" | "error";
上記の例では、status
は文字列型で、値は"success"
または"error"
のどちらかであることが宣言されています。これにより、status
には以下のような値を代入することができます。
status = "success"; status = "error";
Union型はTypeScriptの静的型付けの恩恵を受けることができ、型チェックを厳密に行うことができます。また、Union型を使用することで、より柔軟なコーディングが可能になります。
intersection[編集]
JavaScriptには「intersection」という機能はありませんが、TypeScriptでは利用可能です。
「intersection」は、複数の型を結合することで新しい型を作成する方法です。結合された型は、それらのすべての型のメンバーを持ちます。
例えば、以下のように Person
と Serializable
という2つのインターフェースがあるとします。
interface Person { name: string; age: number; } interface Serializable { serialize(): string; }
これら2つのインターフェースを結合して、新しいインターフェース PersonSerializable
を作成することができます。
type PersonSerializable = Person & Serializable;
PersonSerializable
は、 Person
と Serializable
の両方のメンバーを持ちます。したがって、 name
、 age
、および serialize
の3つのメンバーがあります。
const person: PersonSerializable = { name: "John", age: 30, serialize() { return `${this.name}, ${this.age}`; } };
このように、 intersection
を使用することで、異なる型の機能を1つの型にまとめることができます。
type[編集]
type」はTypeScriptにおける型の定義方法の1つであり、JavaScriptには存在しません。 JavaScriptには動的型付けが採用されており、変数や関数の引数・戻り値に型を指定することができません。一方、TypeScriptでは静的型付けが採用されており、コード内で変数や関数の型を定義することができます。 「type」を使うことで、既存の型から新しい型を定義することができます。例えば、以下のように型エイリアスを定義することができます。
type Age = number;
このように定義した型エイリアスは、その後のコードで型の定義として使用することができます。
function greet(name: string, age: Age) { console.log(`Hello, ${name}! You are ${age} years old.`); } greet('Alice', 30);
このように、型エイリアスを使用することで、コードの可読性を高めたり、同じ型を複数の場所で使用する際に便利になります。また、TypeScriptでは、インターフェースという別の型定義方法も提供されています。
class[編集]
TypeScriptには、クラス型という型があります。これは、クラスのインスタンスを型として指定できるという点で、JavaScriptとは大きく異なります。 クラス型は、JavaScriptのクラスと同様に、オブジェクト指向プログラミングの概念をサポートします。クラス型を使用することで、型安全性を高め、コードの保守性を向上させることができます。
例えば、以下のようなクラスがあるとします。
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } greet() { console.log(`Hello, my name is ${this.name}, and I'm ${this.age} years old.`); } }
このクラスを使用して、以下のようにインスタンスを生成することができます。
const person1 = new Person('Alice', 25); person1.greet(); // Output: Hello, my name is Alice, and I'm 25 years old.
TypeScriptでは、このクラスを型として扱うことができます。
const person2: Person = new Person('Bob', 30); person2.greet(); // Output: Hello, my name is Bob, and I'm 30 years old.
このように、クラス型を使用することで、変数にクラスのインスタンスを代入する際に、そのインスタンスが持つメンバー変数やメソッドにアクセスできるようになります。これにより、より安全で読みやすいコードを書くことができます。
interface[編集]
TypeScriptのinterface
は、JavaScriptには存在しない概念です。interface
は、オブジェクトの形状(shape)を定義するために使用されます。オブジェクトがinterface
で定義された形状に適合しているかどうかを確認するために使用することができます。
JavaScriptには、オブジェクトの形状を定義する方法がありません。そのため、JavaScriptでは、実際にオブジェクトを作成し、プロパティやメソッドが存在するかどうかをチェックする必要があります。
TypeScriptのinterface
は、この問題を解決するために導入されました。interface
を使用することで、オブジェクトの形状を明確に定義することができ、コードの読みやすさや保守性が向上します。
例えば、以下のようにinterface
を使用してオブジェクトの形状を定義することができます。
interface Person { name: string; age: number; address?: string; }
上記のコードでは、Person
というinterface
が定義されています。Person
はname
とage
という必須のプロパティと、オプションのaddress
プロパティを持つオブジェクトの形状を表します。
このinterface
を使用して、以下のようにオブジェクトを作成することができます。
const person: Person = { name: 'Alice', age: 25, };
上記のコードでは、Person
インターフェースを使用して、name
とage
プロパティを持つオブジェクトを作成しています。また、address
プロパティはオプションであるため、省略することができます。
interface
を使用することで、オブジェクトの形状を明確に定義し、プロパティやメソッドが存在するかどうかを簡単にチェックすることができます。
function[編集]
TypeScriptにおいて、関数も型付けされるため、関数型を宣言することができます。JavaScriptには関数型の宣言方法がありませんが、TypeScriptでは型アノテーションまたはインターフェースを使用して関数の型を定義できます。
function add(a: number, b: number): number { return a + b; }
この例では、add
という関数が定義されています。add
関数は2つの引数(a
とb
)を取り、それぞれがnumber
型であることをTypeScriptに示しています。また、戻り値もnumber
型であることを示しています。
TypeScriptでは、シグネチャーと呼ばれる機能を使って、関数の型をより詳細に定義することができます。シグネチャーは、関数の引数と戻り値の型のみを定義し、関数の本体は含まれません。
// シグネチャーを使った関数型の例 type AddFunction = (a: number, b: number) => number; const add: AddFunction = (a, b) => { return a + b; };
型推論[編集]
TypeScriptには、変数宣言時に型の指定がなくても、型推論によって自動的に型を決定する機能があります。この機能はJavaScriptにはありません。
たとえば、次のコードを考えてみましょう。
let myVar = 10;
このコードでは、myVar
に値10
を代入していますが、型の宣言がありません。しかし、TypeScriptはmyVar
をnumber
型として推論します。
同様に、文字列を代入する場合は、string
型、真偽値を代入する場合はboolean
型として推論されます。
let myString = "Hello, TypeScript!"; let myBool = true;
推論された型は、typeof
演算子を使用することで確認することができます。
console.log(typeof myVar); // "number" console.log(typeof myString); // "string" console.log(typeof myBool); // "boolean"
一方、JavaScriptでは、変数の型を指定する方法はありません。また、JavaScriptでは、typeof
演算子によって変数の型を取得することはできますが、この演算子はあくまでも実行時に型を判断するものであり、コードの実行前には型を正確に判断することはできません。
例えば、次のコードを考えてみましょう。
let myVar = 10; console.log(typeof myVar); // "number" myVar = "Hello, JavaScript!"; console.log(typeof myVar); // "string"
この場合、最初にmyVar
にnumber
型の値を代入していますが、後でstring
型の値を代入しています。JavaScriptでは、変数の型が実行時に自由に変更できるため、typeof
演算子でmyVar
の型を取得した結果も、実行時に変化します。
namespace[編集]
TypeScriptのnamespace
はJavaScriptにはない機能であり、TypeScriptの静的型付けシステムの一部です。namespace
を使用することで、グローバル名前空間を汚染することなく、関連する関数、変数、クラスをグループ化できます。
以下は、TypeScriptのnamespace
の例です。
namespace MyNamespace { export const message: string = "Hello, world!"; export function showMessage() { console.log(message); } export class Person { constructor(public name: string, public age: number) {} public sayHello() { console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`); } } }
このnamespace
は、MyNamespace
という名前の名前空間を作成し、message
という変数、showMessage
という関数、そしてPerson
というクラスを含んでいます。export
キーワードは、これらの要素を名前空間外からアクセス可能にするために使用されます。
以下は、上記のnamespace
をJavaScriptに変換した例です。
var MyNamespace; (function (MyNamespace) { MyNamespace.message = "Hello, world!"; function showMessage() { console.log(MyNamespace.message); } MyNamespace.showMessage = showMessage; class Person { constructor(name, age) { this.name = name; this.age = age; } sayHello() { console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`); } } MyNamespace.Person = Person; })(MyNamespace || (MyNamespace = {}));
JavaScriptには、namespace
という概念がないため、上記のコードは、IIFE(Immediately-Invoked Function Expression)というテクニックを使用して、名前空間をエミュレートしています。このテクニックは、名前空間内の変数や関数がグローバルスコープに漏れ出すことを防ぎ、名前の競合を回避するために有用です。また、namespace
内で定義された要素は、MyNamespace
オブジェクトのプロパティとしてアクセスできます。
関数[編集]
TypeScriptの関数は、JavaScriptの関数と同じように動作しますが、いくつかの差異があります。
まず、TypeScriptの関数には、パラメータに型を指定することができます。これにより、関数のパラメータが期待される型と異なる場合に、TypeScriptがコンパイル時にエラーを検出することができます。
また、TypeScriptの関数には、戻り値に型を指定することができます。これにより、関数が返す値の型を定義することができます。
さらに、TypeScriptの関数には、オプションのパラメータやデフォルト値を指定することができます。これらの機能は、JavaScriptでも利用できますが、TypeScriptでは型情報を合わせて指定することができます。
TypeScriptの関数には、ジェネリック型やアロー関数など、JavaScriptには存在しない機能もあります。これらの機能を使うことで、より柔軟な関数を定義することができます。
以上のように、TypeScriptの関数は、JavaScriptの関数と比べて、より型安全で、より柔軟な機能を持っています。
型アノテーションのある関数定義[編集]
以下の例では、パラメータと戻り値の型を明示的に指定しています。
function greet(name: string): string { return "Hello, " + name; }
同じ関数をJavaScriptで書く場合は、型アノテーションは不要です。
function greet(name) { return "Hello, " + name; }
ラムダ式の型アノテーション[編集]
以下の例では、アロー関数のパラメータと戻り値の型を明示的に指定しています。
const greet = (name: string): string => "Hello, " + name;
同じ関数をJavaScriptで書く場合は、型アノテーションは不要です。
const greet = (name) => "Hello, " + name;
型パラメータを使ったジェネリック関数[編集]
以下の例では、T
という型パラメータを使って、配列の中身を逆順にする関数を定義しています。
function reverse<T>(array: T[]): T[] { return array.reverse(); }
同じ関数をJavaScriptで書く場合は、型パラメータを使うことはできません。
// JavaScriptでは型パラメータを使えないため、以下のように書く必要がある。 function reverse(array) { return array.reverse(); }
定義と定義ファイル[編集]
TypeScriptでは、型定義を別のファイルに分離することができます。以下の例では、greet.d.ts
というファイルに、greet
関数の型定義を書いています。
declare function greet(name: string): string;
この型定義ファイルを使用することで、JavaScriptのファイルでもTypeScriptの関数の型情報を利用することができます。
// greet.d.tsの型定義を読み込むことで、greet関数の型情報を利用できる。 console.log(greet("Alice")); // "Hello, Alice"
JavaScriptでは、型定義ファイルを使用することはできません。
定義ファイルの入手[編集]
TypeScriptでサードパーティ製ライブラリーやES2015などの標準ライブラリの型定義ファイルを入手する方法は以下の通りです。
npm
を使って型定義ファイルをインストールするnpm
はNode.jsのパッケージマネージャーであり、多くの型定義ファイルがnpmのパッケージとして提供されています。例えば、jQueryの型定義ファイルは@types/jquery
というパッケージとして提供されています。インストール方法は以下の通りです。npm install --save-dev @types/jquery
- 同様に、ES2015などの標準ライブラリの型定義ファイルも、
@types
スコープ内に存在します。例えば、ES2015の型定義ファイルは@types/es6-shim
というパッケージとして提供されています。以下のコマンドでインストールできます。 npm install --save-dev @types/es6-shim
- 型定義ファイルを手動でダウンロードする
- もし、npmに型定義ファイルが存在しない場合や、npmを使用しない場合は、型定義ファイルを手動でダウンロードすることもできます。例えば、jQueryの型定義ファイルはDefinitelyTypedというGitHubリポジトリで管理されています。以下のコマンドでリポジトリをクローンして、
index.d.ts
を手動で取得できます。 git clone https://github.com/DefinitelyTyped/DefinitelyTyped.git cd DefinitelyTyped/types/jquery/ cat index.d.ts
- 同様に、ES2015などの標準ライブラリの型定義ファイルも、DefinitelyTypedリポジトリ内に存在します。
- もし、npmに型定義ファイルが存在しない場合や、npmを使用しない場合は、型定義ファイルを手動でダウンロードすることもできます。例えば、jQueryの型定義ファイルはDefinitelyTypedというGitHubリポジトリで管理されています。以下のコマンドでリポジトリをクローンして、
定義ファイルの生成[編集]
TypeScriptの定義ファイルの生成方法には、以下の2つの方法があります。
--declaration
フラグを使用する方法- TypeScriptのコンパイラには、
--declaration
フラグを使用して、定義ファイルを生成することができます。このフラグを指定すると、TypeScriptのコンパイラが、.ts
ファイルをコンパイルした際に、.d.ts
ファイルを同時に生成します。 - 以下は、
greeter.ts
というファイルからgreeter.js
とgreeter.d.ts
を生成する例です。 tsc --declaration greeter.ts
- 生成された
greeter.d.ts
ファイルは、以下のようになります。 declare function greeter(person: string): string;
- TypeScriptのコンパイラには、
dts-gen
ツールを使用する方法dts-gen
は、TypeScriptのコードから定義ファイルを生成するためのツールです。このツールを使用するには、まずdts-gen
をグローバルにインストールします。npm install -g dts-gen
- 次に、生成したい
.ts
ファイルを含むプロジェクトのルートディレクトリで、以下のコマンドを実行します。 dts-gen --name myLib --project .
--name
フラグで指定した名前のディレクトリが作成され、そのディレクトリに.d.ts
ファイルが生成されます。生成されたファイルは、/// <reference path="./typings/index.d.ts" />
のような参照ディレクティブを含んでいるため、必要に応じて修正する必要があります。
以上の方法は、TypeScriptのプロジェクトで定義ファイルを生成する方法です。一方、JavaScriptでは、定義ファイルを生成する標準的な方法はありません。しかし、JSDocを使用して、関数やオブジェクトの型情報をドキュメントとして記述することで、JavaScriptのコードにも型情報を付与することができます。
定義ファイルの書式[編集]
TypeScriptの定義ファイルの書式は、以下のようになっています。
declare function functionName(param1: type1, param2: type2): returnType;
このように、declare
キーワードを用いて、関数や変数の宣言を行います。また、関数の引数や戻り値には、型アノテーションを付与することができます。
例えば、以下はgreeter
関数の定義ファイルの例です。
declare function greeter(person: string): string;
一方、JavaScriptには、定義ファイルの書式は存在しません。代わりに、JSDocと呼ばれるドキュメントコメントを使用して、関数や変数の型情報を記述することができます。
以下は、JSDocを使用してgreeter
関数に型情報を付与する例です。
/** * @param {string} person - The name of the person. * @returns {string} - The greeting message. */ function greeter(person) { return "Hello, " + person; }
このように、@param
タグや@returns
タグを使用して、引数や戻り値の型情報を記述します。
ただし、JavaScriptのJSDocは、TypeScriptの定義ファイルのようにコンパイル時に静的な型チェックを行うわけではないため、注意が必要です。
TSDoc[編集]
TSDocは、TypeScriptのためのドキュメンテーションコメント記法です。TSDocは、JSDocと同じように、ソースコード内にドキュメンテーションコメントを記述するための標準的な形式を提供します。
TSDocは、TypeScriptコードにおいて、型情報やパラメーター、戻り値などの情報を含むコメントを書くことができます。これにより、開発者は、TypeScriptコードを使用する際に、より詳細な情報を把握することができます。
TSDocは、TypeScriptの型情報に基づいて、APIドキュメントを自動的に生成することができます。これにより、開発者は、手作業でドキュメンテーションを作成する手間を省くことができます。
TSDocは、TypeScriptの公式ドキュメンテーションにも使用されており、広く採用されています。
クラス[編集]
JavaScriptにECMAScript2015(ES6)で導入された、キーワード class (クラス)を TypeScript もサポートしています。
- コード例
class Hello { name: string; constructor(name: string = "world") { this.name = name; } toString(): string { return `Hello ${this.name}`; } print(): void { console.log(String(this)); } } const hello: Hello = new Hello(); hello.print(); const hello2: Hello = new Hello("my friend"); hello2.print(); console.log( `typeof Hello === ${typeof Hello} Object.getOwnPropertyNames(hello) === ${Object.getOwnPropertyNames(hello)} ` );
- 表示結果
Hello world Hello my friend typeof Hello === function Object.getOwnPropertyNames(hello) === name
- クラスのメンバーには、型を伴った宣言が必要です。
少しまとまったサイズのクラス[編集]
Ruby#ユーザー定義クラスの都市間の大圏距離を求めるメソッドを追加した例を、TypeScriptに移植。
- ユーザー定義クラス
class GeoCoord { longitude: number; latitude: number; constructor(longitude: number = 0, latitude: number = 0) { // console.info(`GeoCoord::constructor${longitude} ${latitude}`); return Object.assign(this, { longitude, latitude }); } toString(): string { let ew = "東経"; let ns = "北緯"; let long = this.longitude; let lat = this.latitude; if (long < 0.0) { ew = "西経"; long = -long; } if (lat < 0.0) { ns = "南緯"; lat = -lat; } return `(${ew}: ${long}, ${ns}: ${lat})`; } distance(other: GeoCoord): number { const i = Math.PI / 180; const r = 6371.008; return ( Math.acos( Math.sin(this.latitude * i) * Math.sin(other.latitude * i) + Math.cos(this.latitude * i) * Math.cos(other.latitude * i) * Math.cos(this.longitude * i - other.longitude * i) ) * r ); } } const Sites = { "東京駅": [139.7673068, 35.6809591], "シドニー・オペラハウス": [151.215278, -33.856778], "グリニッジ天文台": [-0.0014, 51.4778], }; for (const prop in Sites) { // console.log(`${prop}: ${Sites[prop]}`); Sites[prop] = new GeoCoord(Sites[prop][0], Sites[prop][1]); console.log(`${prop}: ${Sites[prop]}`); } const keys: string[] = Object.keys(Sites); const len = keys.length; keys.forEach(function (x, i) { let y = keys[(i + 1) % len]; console.log(`${x} - ${y}: ${Sites[x].distance(Sites[y])} [km]`); });
- 実行結果
東京駅: (東経: 139.7673068, 北緯: 35.6809591) シドニー・オペラハウス: (東経: 151.215278, 南緯: 33.856778) グリニッジ天文台: (西経: 0.0014, 北緯: 51.4778) 東京駅 - シドニー・オペラハウス: 7823.269299386704 [km] シドニー・オペラハウス - グリニッジ天文台: 16987.2708377249 [km] グリニッジ天文台 - 東京駅: 9560.546566490015 [km]
TypeScriptの高度な機能[編集]
TypeScriptにあってJavaScriptにないキーワード キーワード 説明 type
型エイリアスを定義するために使用されます。 interface
オブジェクトの形状を定義するために使用されます。 class
クラスを定義するために使用されます。 abstract
抽象クラスや抽象メソッドを定義するために使用されます。 implements
インターフェイスを実装するクラスを定義するために使用されます。 enum
列挙型を定義するために使用されます。 namespace
名前空間を定義するために使用されます。 module
モジュールを定義するために使用されます。 import
外部モジュールからエクスポートされた変数や関数をインポートするために使用されます。 export
モジュールから変数や関数をエクスポートするために使用されます。 as
型キャストを行うために使用されます。 readonly
変数やプロパティを読み取り専用にするために使用されます。 never
値が存在しないことを表すために使用されます。 unknown
値の型が不明なことを表すために使用されます。 keyof
オブジェクトのキーを取得するために使用されます。 in
オブジェクトに指定されたプロパティがあるかどうかを判断するために使用されます。 infer
型変数を推論するために使用されます。 Exclude
一方の型にあるが他方の型にない型を取得するために使用されます。 Partial
オブジェクトの全てのプロパティをオプションにするために使用されます。 Required
オブジェクトの全てのプロパティを必須にするために使用されます。 Pick
オブジェクトから指定したプロパティのみを取得するために使用されます。 Record
キーと値のペアを持つオブジェクトを作成するために使用されます。 Omit
オブジェクトから指定したプロパティを削除するために使用されます。 ReturnType
関数の戻り値の型を取得するために使用されます。
モジュールと名前空間[編集]
// myModule.ts export const myFunction = () => { console.log('Hello from myFunction!'); } export interface MyInterface { name: string; age: number; } // main.ts import { myFunction, MyInterface } from './myModule'; myFunction(); const myObject: MyInterface = { name: 'John', age: 30, };
このコードは、TypeScriptにおけるモジュールの使い方の例です。
JavaScriptでもES6からは、export
キーワードやimport
キーワードを使用してモジュールを定義することができるようになりました。しかし、TypeScriptでは、これらのキーワードに加えて、型定義も一緒に書くことができます。
myModule.ts
では、export
キーワードを使用してmyFunction
とMyInterface
を外部に公開しています。myFunction
は単純な関数で、console.log
でメッセージを表示します。MyInterface
は、name
とage
という2つのプロパティを持つインターフェースです。
main.ts
では、myModule.ts
からmyFunction
とMyInterface
をimport
しています。そして、myFunction
を呼び出し、MyInterface
を使ってオブジェクトを作成しています。
TypeScriptのモジュール機能は、JavaScriptのものとほぼ同じですが、型定義を含めることで、コードの安全性と保守性を向上させることができます。
アノテーションとデコレータ[編集]
class MyClass { @myDecorator public myProperty: string; constructor(@myParameterDecorator private _myParameter: number) { this.myProperty = 'Hello, world!'; } @myMethodDecorator public myMethod(): void { console.log(this._myParameter); } } function myDecorator(target: any, key: string) { // do something with target and key } function myMethodDecorator(target: any, key: string, descriptor: PropertyDescriptor) { // do something with target, key, and descriptor } function myParameterDecorator(target: any, key: string, index: number) { // do something with target, key, and index }
このコードは、TypeScriptにおけるアノテーションとデコレータの使い方の例です。
デコレータは、クラスのプロパティやメソッド、パラメーターに対して、実行時にカスタム処理を追加するための構文です。アノテーションは、特定の型や属性を指定するための構文です。
このコードでは、@myDecorator
、@myMethodDecorator
、@myParameterDecorator
という3つのデコレータを使用しています。@myDecorator
は、MyClass
クラスのmyProperty
プロパティに適用され、@myMethodDecorator
はmyMethod
メソッドに適用されています。@myParameterDecorator
は、MyClass
クラスの_myParameter
パラメーターに適用されています。
それぞれのデコレータ関数内では、引数として与えられたtarget
、key
、descriptor
、index
というオブジェクトにアクセスして、必要な処理を行います。たとえば、@myDecorator
デコレータ内では、target
とkey
を使って、MyClass
クラスのmyProperty
プロパティに対するカスタム処理を追加することができます。
また、MyClass
のコンストラクターでは、@myParameterDecorator
を使用して、_myParameter
パラメーターに対するカスタム処理を追加しています。これにより、コンストラクターが実行される前に、パラメーターに対するチェックや変換を行うことができます。
JavaScriptにおいては、デコレータに対応する構文はありませんが、TypeScriptのデコレータはJavaScriptのプロトタイプチェーンを利用して実現されています。また、アノテーションに相当するものもありません。
オプショナルなプロパティとreadonly修飾子[編集]
interface MyInterface { readonly id: number; name: string; age?: number; } const myObject: MyInterface = { id: 1, name: 'John', }; // Cannot assign to 'id' because it is a read-only property. // myObject.id = 2; myObject.age = 30;
このコードは、TypeScriptにおけるオプショナルなプロパティとreadonly
修飾子の使い方の例です。
MyInterface
インターフェースには、3つのプロパティが定義されています。id
プロパティはreadonly
修飾子が付与されており、書き換えができないようになっています。name
プロパティは必須のプロパティであり、age
プロパティはオプショナルのプロパティです。
myObject
はMyInterface
型のオブジェクトであり、id
とname
プロパティが指定されています。しかし、id
プロパティはreadonly
修飾子が付いているため、後から値を変更することはできません。そのため、myObject.id = 2;
のように書き換えしようとすると、エラーが発生します。
一方、age
プロパティはオプショナルのため、必須ではありません。そのため、myObject.age = 30;
のように後からプロパティを追加することができます。
JavaScriptにおいては、readonly
修飾子に相当するものはありませんが、オブジェクトのプロパティを書き換えないようにするには、Object.freeze()
を使用することができます。また、オプショナルなプロパティに相当するものもありませんが、JavaScriptではオブジェクトのプロパティが存在しない場合、そのプロパティにアクセスするとundefined
が返されます。
列挙型[編集]
enum Color { Red, Green, Blue, } function printColor(color: Color) : void { switch (color) { case Color.Red: console.log('Red'); break; case Color.Green: console.log('Green'); break; case Color.Blue: console.log('Blue'); break; // default 節がないのは網羅性を担保するため } } printColor(Color.Red);
このコードは、列挙型(enum)を使用して、TypeScriptで列挙値を扱う方法を示しています。
列挙型は、固定値の集合を表すための型であり、定数のように扱えます。TypeScriptにおける列挙型は、JavaScriptのオブジェクトに近いものですが、列挙型には定数に対して名前を与えることができます。
この例では、Color
という名前の列挙型を定義し、3つの値(Red、Green、Blue)を持たせています。関数printColor
は、Color
型の引数を受け取り、その値が何であるかに応じて、対応する色の文字列をコンソールに出力します。
このコードには default
節がないため、すべての enum Color
のメンバーに対して switch
文での処理が定義されていないと、TypeScript コンパイラがエラーを出力します。つまり、 enum Color
に新しいメンバーを追加するときは、すべての場合分けを考慮して switch
文を更新する必要があります。
そのため、このコードでは網羅性が担保されており、メンバーの追加などの変更があった場合にもコンパイルエラーで指摘されるので、開発者が見落としを防ぐことができます。
JavaScriptには列挙型の概念がないため、同じような機能を実現するためには、オブジェクトや配列を使用することが一般的です。例えば、以下のようなconst
オブジェクトを定義して列挙型の代わりに使用することができます。オブジェクトよりTypeScriptの列挙型が優れている点としては、エディターの自動補完機能や、スイッチ文による型安全の検査が利用でき、開発効率の向上に役立つことが挙げられます。
const Color = { Red: 0, Green: 1, Blue: 2, }; const myColor = Color.Red; function printColor(color) { switch (myColor) { case Color.Red: console.log('Red'); break; case Color.Green: console.log('Green'); break; case Color.Blue: console.log('Blue'); break; } } printColor(Color.Red);
ただし、TypeScriptの列挙型は、エディターの自動補完機能や、スイッチ文による型安全の検査を提供するなど、開発効率の向上に役立ちます。
型の合成[編集]
type MyType = { name: string; age: number; }; type MyOptionalType = Partial<MyType>; type MyReadOnlyType = Readonly<MyType>; type MyCompositeType = MyType & MyOptionalType & MyReadOnlyType; const myObject: MyCompositeType = { name: 'John', age: 30, };
このコードは、TypeScriptにおける型の合成の例です。
まず、MyType
という名前の型を定義しています。この型は、name
とage
という2つのプロパティを持つオブジェクト型です。
次に、MyOptionalType
という名前の型を定義しています。この型は、MyType
型のすべてのプロパティをオプションにしたもので、Partial
というジェネリック型を使用して定義されています。つまり、MyOptionalType
型を持つオブジェクトは、name
とage
の両方、あるいはいずれかのプロパティを持っているかもしれないということです。
その後、MyReadOnlyType
という名前の型を定義しています。この型は、MyType
型のすべてのプロパティを読み取り専用にしたもので、Readonly
というジェネリック型を使用して定義されています。つまり、MyReadOnlyType
型を持つオブジェクトのプロパティは、読み取り専用であるため、値を変更することはできません。
最後に、MyCompositeType
という名前の型を定義しています。この型は、MyType
型とMyOptionalType
型とMyReadOnlyType
型をすべて組み合わせたものです。つまり、MyCompositeType
型を持つオブジェクトは、name
とage
の両方、あるいはいずれかのプロパティを持っているかもしれず、すべてのプロパティが読み取り専用であるということです。
最後に、myObject
という名前のオブジェクトを定義し、MyCompositeType
型で型注釈しています。myObject
は、name
が'John'
で、age
が30
であるオブジェクトであり、すべてのプロパティが読み取り専用であるため、プロパティの値を変更することはできません。
JavaScriptには、型の合成の概念はありません。しかし、JavaScriptでは、複数のオブジェクトを結合して新しいオブジェクトを作成するために、オブジェクトのスプレッド演算子(...
)が使用できます。例えば、以下のようにして、Object.assign()
メソッドを使用して、複数のオブジェクトを結合することができます。
const myObject = Object.assign({}, obj1, obj2, obj3);
TypeScriptの開発環境[編集]
TypeScriptには様々な開発環境がありますが、以下に代表的な方法を示します。
TypeScriptのIDE[編集]
TypeScriptのIDEとしては、以下のようなものがあります。
- Emacs
- Vim
- Visual Studio Code
- WebStorm
- Atom
- Sublime Text 3
これらのIDEはTypeScriptの構文ハイライトや、型チェック、自動補完などの機能を備えています。特にVisual Studio CodeはTypeScriptの開発に最適化されており、TypeScriptのデバッグ機能も利用可能です。
デバッグ方法[編集]
TypeScriptをデバッグする場合、以下のような方法があります。
- ブラウザのデベロッパーツールを利用する(主にフロントエンド開発)
- VSCodeのデバッグ機能を利用する(主にバックエンド開発)
フロントエンド開発においては、ブラウザの開発者ツールを利用することが一般的です。開発者ツールを起動し、ブレークポイントを設定することで、TypeScriptのコードをステップ実行することができます。
バックエンド開発においては、Visual Studio Codeのデバッグ機能を利用することが一般的です。VSCodeでプロジェクトを開き、ブレークポイントを設定した上で、デバッグモードで起動することで、TypeScriptのコードをデバッグすることができます。
テスト方法[編集]
TypeScriptでのテスト方法としては、以下のような方法があります。
- Jest
- Mocha + Chai
- AVA
これらのツールは、TypeScriptのテストをサポートしています。Jestは特にTypeScriptとの親和性が高く、設定の手間が少ないことが特徴です。
テストを書く際は、describeやit、expectなどのAPIを使い、テストスクリプトを記述します。テストコードは通常、TypeScriptで書かれるため、テストランナーによってTypeScriptからJavaScriptへのコンパイルが自動的に行われます。
以上が、TypeScriptの開発環境、デバッグ方法、テスト方法についての簡単な紹介です。
TypeScriptとフロントエンド開発[編集]
React、Angular、Vue は全て JavaScript フレームワークで、それぞれの違いがあります。TypeScriptとともに使用されたときの主な違いは次の通りです。
- React
- React は Facebook によって開発され、コンポーネントベースのUIライブラリです。React はバーチャルDOMを使用して高速かつ効率的にレンダリングし、データフローは親から子への単方向の流れです。React Community によって開発されたプラグインやカスタムコンポーネントを使用することにより、React の機能を拡張することができます。
- Angular
- Angular は Google によって開発された TypeScript ベースのフレームワークで、アプリケーションのための完全な開発プラットフォームです。Angular は双方向のデータバインディング、単一のコンポーネント、タイプセーフの依存性注入、テンプレートとダイレクティブ、モジュールなどの一連の機能を備えています。
- Vue
- Vue は Evan You によって開発された次世代のフロントエンドJavaScriptフレームワークで、主に view に特化していますが、機能的なWebアプリケーションで使われることもあります。Vue は React に似た仮想DOMベースのアプローチに基づいています。Vue はディレクティブによるバインディング、コンポーネントのカスタム要素、フィルタ機能などの機能を備えています。
全体的に、ReactとVueはより軽量な方法でコンポーネントを作成し、アプリケーションの機能を拡張することができ、Angularは完全な開発プラットフォームであり、より広範なアプリケーションを開発するために使用されます。 TypeScript との統合に関しては、Vue はネイティブでサポートしており、ReactとAngularも公式に TypeScript をサポートしています。これにより、型付き言語の強力な機能を活用して、エラーを捕捉し、コードの信頼性と保守性を向上させることができます。
仮想DOM |
仮想DOMは、ReactのようなUIライブラリで広く使われている技術で、実際のブラウザのDOMを反映するJavaScriptのオブジェクトの代わりに、仮想的なオブジェクトのツリーに変更を加えて、必要なときに再描画することによって、ウェブページのレンダリングを高速化します。
仮想DOMは、実際のDOMにアクセスするための時間やリソースを節約し、必要な場合にのみ更新することができるため、改善されたパフォーマンスを実現します。仮想DOMは、Reactのようなライブラリでは不可欠な要素で、TSプログラミングにおいても、高速でスケーラブルなWebアプリケーションの開発に不可欠な技術となっています。 |
React[編集]
React はコンポーネントベースの JavaScript ライブラリです。TypeScript を使う場合、プロジェクトを作成する前に、create-react-app
を使って TypeScript テンプレートを作成する必要があります。
以下のコマンドを順番に入力し、React プロジェクトを作成し、TypeScript を有効にします。
npx create-react-app my-app --template typescript cd my-app
このコマンドで、my-app
ディレクトリ内に組み込みの TypeScript 設定が含まれる React アプリケーションが作成されます。
次に、src/App.tsx
ファイルを次のように変更して、TypeScript の機能を使用することができます。
import React from 'react'; interface Props { name: string; } const App: React.FC<Props> = ({ name }) => { return <div>Hello, {name}!</div>; }; export default App;
Angular[編集]
Angular は、TypeScript を含む JavaScript フレームワークです。プロジェクトを作成する前に、@angular/cli
をグローバルにインストールする必要があります。
以下のコマンドを順番に実行し、Angular プロジェクトを作成します。
npm install -g @angular/cli ng new my-app --minimal --strict --skip-tests --skip-git cd my-app
--minimal
フラグは、初期アセットを簡素化し、--strict
フラグは、TypeScript の厳格な機能を有効にします。--skip-tests
フラグは、ユニットテストファイルを生成しないようにし、--skip-git
フラグは、Git リポジトリを生成しないようにします。
次に、src/app/app.component.ts
ファイルを次のように変更して、TypeScript の機能を使用することができます。
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: `<div>Hello, {{ name }}!</div>` }) export class AppComponent { name = 'Angular'; }
Vue[編集]
Vue.js は、コンポーネントベースの JavaScript フレームワークで、Angular、React などのようなフレームワークと同様に、TypeScript をサポートしています。ただし、Vue.js プロジェクトで TypeScript を使用するためには、単一ファイルコンポーネントのコンパイルなどの様々な設定を行う必要があります。
ここでは、Vue CLI を使用して Vue.js + TypeScript テンプレートを作成する方法を示します。まず、@vue/cli
パッケージをグローバルにインストールします。
npm install -g @vue/cli
次に、vue create
コマンドを実行して Vue.js プロジェクトを作成します。
vue create my-app
このコマンドを実行すると、いくつかのプリセットが表示されますが、Manually select features
を選択し、TypeScript
を選択します。
プロジェクトが作成されたら、src/App.vue
ファイルを次のように変更して、TypeScript の機能を使用することができます。
<template> <div>Hello, {{ name }}!</div> </template> <script lang="ts"> import { Vue, Component } from 'vue-property-decorator'; @Component export default class App extends Vue { name = 'Vue'; } </script>
注意点としては、<script>
タグに lang="ts"
属性を追加する必要があることです。さらに、Vue.js でのサポートや設定については、vue-class-component
などのライブラリを使用する必要があることもあります。完全な設定手順については、Vue.js 公式ドキュメントを参照してください。
TypeScriptとバックエンド開発[編集]
TypeScriptとNode.js[編集]
TypeScriptとExpress[編集]
TypeScriptとNestJS[編集]
TypeScriptの実践的な活用例[編集]
実践的なサンプルコード[編集]
TypeScriptでの開発のメリットとデメリット[編集]
まとめ[編集]
TypeScriptのまとめ[編集]
次に学ぶべきこと[編集]
.d.ts[編集]
.d.ts
ファイルは、TypeScriptの型宣言ファイルであり、通常、外部のJavaScriptライブラリをTypeScriptで使用する際に使用します。.d.ts
ファイルは、JavaScriptライブラリの関数、クラス、オブジェクト、変数などの名前と型情報を提供し、TypeScriptがこれらのライブラリをより安全に使うことができるようにします。
例えば、外部ライブラリの関数に渡す引数の型に対して、TypeScript のコンパイラは検査を実行します。もし、外部ライブラリを使用しているコードの中で、渡された引数が予期される型と異なっている場合、TypeScriptはコンパイル時にエラーを報告します。
.d.ts
ファイルは、手動で作成することもできますが、もしライブラリがnpmパッケージである場合、@types
スコープに公開されている別のパッケージから、簡単に取得することができます。例えば、lodash
ライブラリをTypeScriptで使用する際には、@types/lodash
パッケージをインストールすることによって、.d.ts
ファイルを手動で作成する代わりに、TypeScriptが自動的に型情報を認識できます。
制御構造[編集]
TypeScriptは、JavaScriptと同じ制御構造の構文を持ちます。
条件文[編集]
- if文の例
let num: number = 0.0 / 0.0 if (num < 0.0) { console.log('負') } else if (num > 0.0) { console.log('正') } else if (num == 0.0){ console.log('零') } else { console.log('NaN') }
- 実行結果
NaN
- switch文の例
let num: number = 0.0 / 0.0; switch (true) { case num < 0.0: console.log("負") break case num > 0.0: console.log("正") break case num == 0.0: console.log("零") break default : console.log("NaN") }
- 実行結果
NaN
反復文[編集]
型アノテート以外は、JavaScriptと違いはありません。
- while文
let i: number = 0; while (i < 10) { console.log(i); i++; }
- do-while文
let i: number = 0; do { console.log(i); i++; } while (i < 10);
- for文
for (let i: number = 0; i < 10; i++) { console.log(i); }
- for-in文
const obj: object = { x: 2, y: 3, z: 5 }; for (const prop in obj) { console.log(`${prop}: ${obj[prop]}`); } // x: 2 // y: 3 // z: 5
- for-of文
const ary: string[] = [..."XYZ"]; for (const el of ary) { console.log(el); } // X // Y // Z
スプライス構文 [..."XYZ"]
を使うには
npx tsc --target es2015
とES2015以降をターゲットに指定する必要がありました。
ES2015以前で、スプライス構文相当のことを行うには
[..."XYZ"]
を
"XYZ".split("")
に置換えます。これで、同じ
['X', 'Y', 'Z']
となります。
スプライス構文は、他にも引数リストなどでも使えるので、この方法が全てのスプライス構文の置換えにはなりません。
ちなみに Babal は、
const ary: string[] = [..."XYZ"];
から
"use strict"; function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } var ary = _toConsumableArray("XYZ");
を生成します。
tsconfig.json [編集]
tsc は、tsconfig.json で動作を変える事ができます。
最初は
npx tsc --init
とすると雛形が生成されます。
設定項目(一部):
noImplicitAny
(boolean): 暗黙的にany
と推論された場合は即座にエラーにする。strictNullChecks
(boolean):undefined
やnull
の可能性がある式に対して操作を試みることを禁止する。strictFunctionTypes
(boolean): 関数の引数の型、型変数を持つクラスの型引数に対するチェックが厳しくなる。strictBindCallApply
(boolean):Function
及びそのサブタイプに対するbind
、call
、apply
の呼び出しが厳格化される。strictPropertyInitialization
(boolean): 定義時にもコンストラクタ内でも初期化されないクラスのインスタンス変数をエラーにする。noImplicitThis
(boolean):this
がany
と推論される場合はエラーにする。strict
(boolean):noImplicitAny
、strictNullChecks
、strictFunctionTypes
、strictBindCallApply
、strictPropertyInitialization
、noImplicitThis
を全て有効化する。
附録[編集]
TypeScript チートシート[編集]
/** * 変数宣言 * @var x - 変数 * @type {number} */ let x = 5; x = 6; // 可 /** * 定数宣言 * @var y - 定数 * @type {number} */ const y = 5; // y = 6; // 不可 /** * 型アノテーションを伴った宣言 * @var z - 変数 * @type {number} */ let z: number = 5; /** * メソッド * @param {number} x - 引数 * @returns {number} - 返り値 */ function f1(x: number): number { return x * x; } /** * メソッド * @param {*} x - 引数 * @returns {void} */ function f2(x) { console.log(x); } // 不正:引数に型アノテーションがない /** * メソッド * @param {*} x - 引数 * @returns {void} */ function f3(x: any): void { console.log(x); } // 適合:なんでもこい /** * 型エイリアス * @typedef {number} T */ type T = number; /** * 変数宣言 * @var u - 変数 * @type {T} */ let u: T; /** * ジェネリック関数 * @template T * @param {T[]} items - 配列 * @returns {T[]} - 配列 */ function gf<T>(items: T[]): T[] {} /** * ユニオン型 * @var {U} * @type {number | string} */ type U = number | string; /** * 交差型 * @var {Q} * @type {number & string} */ type Q = number & string; /** * タプル型 * @var {R} * @type {[string, number]} */ type R = [string, number]; // データ構造 [1, 2, 3]; // 配列リテラル /** * 構造化代入: パターンマッチによる配列の展開。 * @var {x1} * @type {number} * @var {y1} * @type {number} * @var {z1} * @type {number} */ const [x1, y1, z1] = [1, 2, 3]; // const x2, y2, z2 = [1, 2, 3]; // アカン奴:変数 z2 が配列で初期化される(x2, y2 は undefined) /** * 配列要素の参照 * @var {number[]} * @type {Array<number>} */ const ary = [2, 3, 5, 7, 11]; ary[3]; // 添字を使った配列要素の参照 // 制御構文 /** * 条件分岐 * @param {boolean} 条件式 - 条件 * @returns {void} */ if (条件式) { 文真; } else { 文偽; } /** * 条件分岐 * @param {boolean} 条件式 - 条件 * @returns {void} */ if (条件式) { 文真; } // elseなし /** * switch文 * @param {any} 式 - 式 * @returns {void} */ switch (式) { case 式1: 文1; break; // ... case 式n: 文n; break; default: 文d; } /** * ループ * @var {number} x - 変数 * @type {number} */ let x = 0; while (x < 5) { console.log(x); x++; } /** * ループ * @var {number} i - 変数 * @type {number} */ for (let i: number = 0; i < 10; i++) { console.log(i); } // オブジェクト指向 /** * クラス * @class C */ class C { /* * メンバー変数1 * @var member1 - メンバー変数 * @type {number} */ member1: number; /** * メンバー変数2 * @var member2 - メンバー変数 * @type {number} */ member2: number; /** * コンストラクタ * @param {...any} 仮引数リスト - 引数 * @constructor */ constructor(仮引数リスト) { /* ... */ } /** * メソッド1 * @returns {void} */ method1() { /* ... */ } /** * メソッド2 * @returns {void} */ method2() { /* ... */ } } /** * インスタンス化 * @var {C} obj - オブジェクト */ const obj: C = new C(実引数リスト);
コードギャラリー[編集]
エラトステネスの篩[編集]
/** * エラトステネスの篩を用いて、n以下の素数を全て出力する関数 * @param {number} n 素数を探す範囲の上限値 * @returns {number[]} - 素数の配列 */ function eratosthenes(n: number): number[] { const sieve: boolean[] = new Array(n + 1).fill(true); sieve[0] = false; sieve[1] = false; const result: number[] = []; for (let i = 2, len = sieve.length; i < len; i++) { if (!sieve[i]) { continue; } result.push(i); for (let j = i * 2; j < len; j += i) { sieve[j] = false; } } return result; } // Example usage console.log(eratosthenes(100));
最大公約数と最小公倍数[編集]
/** * 2つの整数の最大公約数を再帰的に求める関数 * @param {number} m - 整数1 * @param {number} n - 整数2 * @returns {number} - 整数1と整数2の最大公約数 */ function gcd2(m: number, n: number): number { if (n === 0) { return m; } else { return gcd2(n, m % n); } } /** * 複数の整数の最大公約数を求める関数 * @param {...number} ints - 最大公約数を求める整数配列 * @returns {number} - 与えられた整数配列の最大公約数 */ function gcd(...ints: number[]): number { return ints.reduce((x, y) => gcd2(x, y)); } /** * 2つの整数の最小公倍数を求める関数 * @param {number} m - 整数1 * @param {number} n - 整数2 * @returns {number} - 整数1と整数2の最小公倍数 */ function lcm2(m: number, n: number): number { return m * n / gcd2(m, n); } /** * 複数の整数の最小公倍数を求める関数 * @param {...number} ints - 最小公倍数を求める整数配列 * @returns {number} - 与えられた整数配列の最小公倍数 */ function lcm(...ints: number[]): number { return ints.reduce((x, y) => lcm2(x, y)); } /** * テストコード */ function main(): void { console.log(`gcd2(30, 45) => ${gcd2(30, 45)}`); console.log(`gcd(30, 72, 12) => ${gcd(30, 72, 12)}`); console.log(`lcm2(30, 72) => ${lcm2(30, 72)}`); console.log(`lcm(30,42,72) => ${lcm(30,42,72)}`); } main();
二分法[編集]
/** * 2分法による方程式の数値解を求める関数 * @param {number} low - 下限値 * @param {number} high - 上限値 * @param {(x: number) => number} f - 数値解を求める対象となる関数 * @returns {number} 方程式の数値解 */ function bisection(low: number, high : number, f: (x: number) => number): number { let x = (low + high) / 2; let fx = f(x); if (Math.abs(fx) < +1.0e-10) { return x; } if (fx < 0.0) { low = x; } else { high = x; } return bisection(low, high, f); } /** * テスト用の関数 */ function main() { console.log(bisection(0, 3, (x) => x - 1)); console.log(bisection(0, 3, (x) => x * x - 1)); } main();
- 旧課程(-2012年度)高等学校数学B/数値計算とコンピューター#2分法の例を JavaScript に移植しました。
クラス定義とインスタンス化とメンバー関数[編集]
/** * Hello クラス * @class * @classdesc Hello クラスは、挨拶文を扱うクラスです。 */ class Hello { /** * 挨拶文に含める文字列 * @type {string} */ public s: string; /** * Hello クラスのインスタンスを作成します。 * @param {string} s - 挨拶文に含める文字列 (省略可能) */ constructor(s: string = "world") { this.s = s; } /** * 挨拶文を文字列で表現する関数 * @returns {string} 挨拶文の文字列 */ public toString(): string { return `Hello ${this.s}!`; } /** * 挨拶文を出力する関数 * @returns {void} */ public print(): void { console.log(this.s); } } /** * テスト用の関数 */ function main(): void { const hello1: Hello = new Hello(); console.log(hello1.toString()); hello1.print(); const hello2: Hello = new Hello("my friend"); console.log(hello2.toString()); hello2.print(); console.log( ` Hello.constructor.name => ${Hello.constructor.name} hello1 => ${hello1} hello2.s => ${hello2.s} ` ); } main();
このコードは、JavaScriptで Hello クラスを定義し、そのクラスを使ってテストを行うためのコードです。Hello クラスは、挨拶文を扱うクラスであり、挨拶文に含める文字列を引数として受け取ります。引数が省略された場合、デフォルトで "world" という文字列を含めます。
Hello クラスには、toString() メソッドと print() メソッドがあります。toString() メソッドは、"Hello [挨拶文に含める文字列]!" という文字列を返し、print() メソッドは、挨拶文に含める文字列をコンソールに出力します。
また、main() 関数を定義し、この関数を呼び出すことで、Hello クラスを使って挨拶文を作成してコンソールに出力するテストを行うことができます。main() 関数の中では、Hello クラスのインスタンスを2つ作成し、それぞれの toString() メソッドと print() メソッドを呼び出しています。また、Hello クラスの constructor.name プロパティをコンソールに出力して、クラス名が取得できることを確認しています。
関連リンク[編集]
- TypeScript: Typed JavaScript at Any Scale. - 公式サイト
- TypeScript: TS Playground - An online editor for exploring TypeScript and JavaScript
- ^ JSのレベルで出来ません。