TypeScript

出典: フリー教科書『ウィキブックス(Wikibooks)』

メインページ > 工学 > 情報技術 > プログラミング > TypeScript

Wikipedia
Wikipedia
ウィキペディア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
  1. Node.jsをインストールします。
  2. ターミナルで、npm install -g typescriptを実行して、TypeScriptをグローバルにインストールします。
  3. tscコマンドを実行して、TypeScriptをコンパイルします。
Deno
  1. Denoをインストールします。
  2. ターミナルで、deno install -n ts https://deno.land/std/typescript/tsc.tsを実行して、TypeScriptコンパイラをインストールします。
  3. TypeScriptファイルを作成し、tsコマンドを使用してコンパイルします。例:ts file.ts
TypeScript Playground
  1. TypeScript Playgroundにアクセスします( https://www.typescriptlang.org/play )。
  2. 左側のペインにTypeScriptコードを入力します。
  3. 右側のペインには、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 変数名 : 型名 = 初期値 ;
このように明示的型を指定する仕組みを、型アノテーションと言います。
TypeScriptの基本的な型の一覧
説明
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ビット倍精度浮動小数点数です。 実行時に、Number.isInteger()を使って動的に判定することは出来ますが、コンパイル時に整数に限定した型をアノテートすることは出来ません。

どうしても整数に限定した型がほしい場合は、BigInt オブジェクトがあります。 BigInt オブジェクトのリテラルは、123n の様に数値に続けて n を補います。 TSでの型名は bigint です。 bigint と number の間では四則演算や比較演算は出来ません[1]。 Number() あるいは BigInt() で型を合わせてから演算する必要があります。 C言語などは、浮動小数点数に自動変換されますが、JS(=TS)の場合 BigInt は名前の通り多倍長整数なので 10n ** 309n の様な大きな値を、Number() で型変換すると Infinity になってしまいますので、一概に Number に揃えるべきとも言えません。


文字列型(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;

上記の例では、valuestringまたは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」は、複数の型を結合することで新しい型を作成する方法です。結合された型は、それらのすべての型のメンバーを持ちます。

例えば、以下のように PersonSerializable という2つのインターフェースがあるとします。

interface Person {
  name: string;
  age: number;
}

interface Serializable {
  serialize(): string;
}

これら2つのインターフェースを結合して、新しいインターフェース PersonSerializable を作成することができます。

type PersonSerializable = Person & Serializable;

PersonSerializable は、 PersonSerializable の両方のメンバーを持ちます。したがって、 nameage 、および 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が定義されています。Personnameageという必須のプロパティと、オプションのaddressプロパティを持つオブジェクトの形状を表します。

このinterfaceを使用して、以下のようにオブジェクトを作成することができます。

const person: Person = {
  name: 'Alice',
  age: 25,
};

上記のコードでは、Personインターフェースを使用して、nameageプロパティを持つオブジェクトを作成しています。また、addressプロパティはオプションであるため、省略することができます。

interfaceを使用することで、オブジェクトの形状を明確に定義し、プロパティやメソッドが存在するかどうかを簡単にチェックすることができます。

function[編集]

TypeScriptにおいて、関数も型付けされるため、関数型を宣言することができます。JavaScriptには関数型の宣言方法がありませんが、TypeScriptでは型アノテーションまたはインターフェースを使用して関数の型を定義できます。

function add(a: number, b: number): number {
  return a + b;
}

この例では、addという関数が定義されています。add関数は2つの引数(ab)を取り、それぞれが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はmyVarnumber型として推論します。

同様に、文字列を代入する場合は、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"

この場合、最初にmyVarnumber型の値を代入していますが、後で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などの標準ライブラリの型定義ファイルを入手する方法は以下の通りです。

  1. 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
    
  2. 型定義ファイルを手動でダウンロードする
    もし、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リポジトリ内に存在します。
定義ファイルの生成[編集]

TypeScriptの定義ファイルの生成方法には、以下の2つの方法があります。

  1. --declarationフラグを使用する方法
    TypeScriptのコンパイラには、--declarationフラグを使用して、定義ファイルを生成することができます。このフラグを指定すると、TypeScriptのコンパイラが、.tsファイルをコンパイルした際に、.d.tsファイルを同時に生成します。
    以下は、greeter.tsというファイルからgreeter.jsgreeter.d.tsを生成する例です。
    tsc --declaration greeter.ts
    
    生成されたgreeter.d.tsファイルは、以下のようになります。
    declare function greeter(person: string): string;
    
  2. 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キーワードを使用してmyFunctionMyInterfaceを外部に公開しています。myFunctionは単純な関数で、console.logでメッセージを表示します。MyInterfaceは、nameageという2つのプロパティを持つインターフェースです。

main.tsでは、myModule.tsからmyFunctionMyInterfaceimportしています。そして、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プロパティに適用され、@myMethodDecoratormyMethodメソッドに適用されています。@myParameterDecoratorは、MyClassクラスの_myParameterパラメーターに適用されています。

それぞれのデコレータ関数内では、引数として与えられたtargetkeydescriptorindexというオブジェクトにアクセスして、必要な処理を行います。たとえば、@myDecoratorデコレータ内では、targetkeyを使って、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プロパティはオプショナルのプロパティです。

myObjectMyInterface型のオブジェクトであり、idnameプロパティが指定されています。しかし、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という名前の型を定義しています。この型は、nameageという2つのプロパティを持つオブジェクト型です。

次に、MyOptionalTypeという名前の型を定義しています。この型は、MyType型のすべてのプロパティをオプションにしたもので、Partialというジェネリック型を使用して定義されています。つまり、MyOptionalType型を持つオブジェクトは、nameageの両方、あるいはいずれかのプロパティを持っているかもしれないということです。

その後、MyReadOnlyTypeという名前の型を定義しています。この型は、MyType型のすべてのプロパティを読み取り専用にしたもので、Readonlyというジェネリック型を使用して定義されています。つまり、MyReadOnlyType型を持つオブジェクトのプロパティは、読み取り専用であるため、値を変更することはできません。

最後に、MyCompositeTypeという名前の型を定義しています。この型は、MyType型とMyOptionalType型とMyReadOnlyType型をすべて組み合わせたものです。つまり、MyCompositeType型を持つオブジェクトは、nameageの両方、あるいはいずれかのプロパティを持っているかもしれず、すべてのプロパティが読み取り専用であるということです。

最後に、myObjectという名前のオブジェクトを定義し、MyCompositeType型で型注釈しています。myObjectは、name'John'で、age30であるオブジェクトであり、すべてのプロパティが読み取り専用であるため、プロパティの値を変更することはできません。

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): undefinednullの可能性がある式に対して操作を試みることを禁止する。
  • strictFunctionTypes (boolean): 関数の引数の型、型変数を持つクラスの型引数に対するチェックが厳しくなる。
  • strictBindCallApply (boolean): Function及びそのサブタイプに対するbindcallapplyの呼び出しが厳格化される。
  • strictPropertyInitialization (boolean): 定義時にもコンストラクタ内でも初期化されないクラスのインスタンス変数をエラーにする。
  • noImplicitThis (boolean): thisanyと推論される場合はエラーにする。
  • strict (boolean): noImplicitAnystrictNullChecksstrictFunctionTypesstrictBindCallApplystrictPropertyInitializationnoImplicitThisを全て有効化する。

附録[編集]

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」は、まだ書きかけです。加筆・訂正など、協力いただける皆様の編集を心からお待ちしております。また、ご意見などがありましたら、お気軽にトークページへどうぞ。
  1. ^ JSのレベルで出来ません。