メインページ > 工学 > 情報技術 > プログラミング > 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を使用してサーバーサイドアプリケーションを開発するためのオープンソースのランタイム環境であり、GoogleのV8 JavaScriptエンジンを基に構築されています。非同期I/O処理、イベント駆動アーキテクチャ、およびモジュールベースのアプローチなどの特徴を備えています。
特にWebアプリケーションの開発において優れた選択肢となっており、サーバーサイドのJavaScriptを実行することで、クライアント側とサーバー側のコードを同じ言語で統一できます。また、Node.jsは多くのパッケージやライブラリが提供されており、開発の効率性が向上しています。
Node.jsはフロントエンドのJavaScriptフレームワークと組み合わせて、ReactやAngularなどの人気フレームワークと連携することで、フルスタックのWebアプリケーションを開発することが可能です。
多くの企業や開発者によって採用され、オープンソースのプロジェクトとしてコミュニティによる開発が進められています。その結果、Node.jsは高い人気を誇り、柔軟性と拡張性に優れた選択肢として広く活用されています。
Deno
Denoは、オープンソースのランタイム環境であり、JavaScriptやTypeScriptを使用してサーバーサイドアプリケーションを開発するためのプラットフォームです。Node.jsと同様にGoogleのV8 JavaScriptエンジンを採用していますが、非同期I/O処理とイベント駆動アーキテクチャの代わりに、シンプルで安全なAPIを強調しています。
Denoは、Node.jsと比較してよりセキュアなデフォルト設定を採用しており、組み込まれたパッケージマネージャーによって外部の依存関係を管理しています。また、TypeScriptのサポートにおいても優れており、標準でTypeScriptをサポートしています。
異なるアーキテクチャとAPIを提供するため、Denoの使用には学習コストが発生しますが、セキュリティや依存関係の管理において強力な機能を提供しています。そのため、特にセキュリティ上の懸念がある企業やプロジェクトにとって適した選択肢とされています。
TypeScript Playground( https://www.typescriptlang.org/play )
TypeScript Playgroundは、オンラインツールで、ブラウザ上でTypeScriptのコードを作成し、それをコンパイルして実行結果を確認するための手段です。JavaScript開発者がTypeScriptの構文、型、および機能を探索し、学ぶための便利なリソースの一つです。Playgroundを使用することで、TypeScriptのコードを試し、実際にどのように動作するかを確認することができます。
左側にはTypeScriptコードを入力するエディターがあり、コードの入力後には右側にJavaScriptコードのプレビューが表示されます。また、TypeScriptファイルを読み込むことや、ファイルをアップロードしてプレビューを確認することも可能です。
TypeScript Playgroundは、TypeScriptの基本を学ぶための有益なツールであり、導入前に実際にコードを書いて、そのコンパイル結果を確認することができます。これにより、開発者は直感的にTypeScriptの特徴や動作を理解し、学習プロセスを効果的に進めることができます。
トランスパイラとは
トランスパイラ(transpiler)は、一般的にはプログラミング言語のコードを別のプログラミング言語のコードに変換するツールを指します。トランスパイラはコンパイラの一種であり、ソースコードを別のソースコードに変換するプロセスを担当します。これにより、異なる言語間での互換性や特定の言語の機能を利用することが可能になります。

具体的には、トランスパイラは以下のような用途で使用されることがあります:

  • 言語の変換: あるプログラミング言語で書かれたコードを別のプログラミング言語に変換することがあります。例えば、TypeScriptからJavaScriptへの変換、CoffeeScriptからJavaScriptへの変換などが挙げられます。
  • バージョン間の互換性: 新しい言語のバージョンがリリースされた際、既存のコードを新しいバージョンに対応させるための変換が必要です。トランスパイラは、古いバージョンのコードを新しいバージョンに変換する手段を提供します。
  • 構文の最適化: コードをより効率的に実行するために、トランスパイラは構文やコード構造を最適化することがあります。これにより、コードの実行速度が向上したり、特定のルールに基づいて変換が行われたりします。

例えば、TypeScriptはJavaScriptへのトランスパイラが含まれており、TypeScriptの機能を使いながらも、最終的にはブラウザやNode.jsが実行できるJavaScriptに変換されます。同様に、Babelと呼ばれるトランスパイラは、新しいECMAScript標準に基づいたJavaScriptコードを、より広くサポートされている古いバージョンのJavaScriptに変換します。


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では、変数に対して型を指定することができます。これにより、コードの安全性が向上し、読みやすくなります。以下に、変数と型に関する基本的な情報を示します。

変数の宣言 編集

変数を宣言する方法はいくつかありますが、基本的な方法は次の通りです:

let variableName: type;

ここで、variableName は変数の名前であり、type は変数の型です。

型推論 編集

TypeScriptは型推論を行います。つまり、変数に初期値が与えられている場合、TypeScriptはその初期値から型を推論し、その型を変数に割り当てます。例:

let numberVariable = 10; // number型と推論される
let stringVariable = "Hello"; // string型と推論される
明示的な型指定 編集

型推論が十分ではない場合、または変数の型を明示的に指定したい場合は、型アノテーション(Type Annotation)を使用します:

let numberVariable: number = 10;
let stringVariable: string = "Hello";
基本的な型 編集
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型 編集

any 型は、任意の型を持つことを示します。すべての型のスーパーセットであり、型チェックが行われません。

let anyVariable: any = 10;
anyVariable = "Hello"; // 問題なく代入できる
数値型(number) 編集

TypeScriptの数値型はnumber型です。これは整数や浮動小数点数などの数値を扱うことができます。

let integerValue: number = 10; // 整数値
let floatValue: number = 3.14; // 浮動小数点数
= 数値リテラル = 編集

数値リテラルは、コード内で具体的な数値を表現するために使用されます。 これには、10進数、2進数、8進数、16進数などの表記方法があります。

let decimalLiteral: number = 10;      // 10進数
let binaryLiteral: number = 0b1010;   // 2進数(10進数の10と同じ)
let octalLiteral: number = 0o12;      // 8進数(10進数の10と同じ)
let hexadecimalLiteral: number = 0xA; // 16進数(10進数の10と同じ)

これらの数値リテラルを使用することで、異なる進数の数値を直接コードに表現することができます。

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型を使用することができます:

let numberOrString: number | string;
numberOrString = 10; // 問題なく代入できる
numberOrString = "Hello"; // 問題なく代入できる
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を用いて 型エイリアスを定義できます:

type Point = {
    x: number;
    y: number;
};

let point: Point = { x: 10, y: 20 };
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;
};

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の公式ドキュメンテーションにも使用されており、広く採用されています。

TypeScriptの変遷
TypeScript(以下、TS)は、Microsoftによって開発され、JavaScriptのスーパーセットであり、静的型付けをサポートするプログラミング言語です。以下は、TypeScriptの主な変遷の要点です。
  1. 開発の開始(2012年10月):
    • Microsoftによって、Anders Hejlsberg(C#の主要開発者でもあります)などのチームによって開発が開始されました。
    • TypeScriptは、JavaScriptの開発をより大規模で保守可能なものにするための静的型付けなどの機能を提供しました。
  2. 公式リリース(2012年10月):
    • TypeScript 0.8が公式にリリースされ、広く利用可能になりました。
    • 開発者は、TypeScriptを使用してJavaScriptのコードを書くことができるようになり、コンパイラによってJavaScriptに変換されました。
  3. 型注釈とコンパイルオプションの拡充(2013年 - 2014年):
    • TypeScript 1.0がリリースされ、型注釈やコンパイルオプションなど、言語の安定性と柔軟性が向上しました。
  4. ECMAScript 6(ES6)のサポート(2015年):
    • TypeScript 1.5が、ECMAScript 6(またはECMAScript 2015)のサポートを追加しました。
    • アロー関数、ジェネレータ、クラス、モジュールなど、新しいJavaScriptの機能をサポートしました。
  5. 型エイリアス、ジェネリクスの強化(2017年 - 2018年):
    • TypeScript 2.0からは、型エイリアスや非nullableの型など、型の機能が拡充されました。
    • TypeScript 2.3では、条件型やMapped Typesなど、ジェネリクスに関連する新機能が導入されました。
  6. 非同期関数のサポート(2017年 - 2018年):
    • TypeScript 2.1からは、非同期関数のサポートが向上し、asyncおよびawaitキーワードが導入されました。
  7. Strict Null Checking(2017年 - 2018年):
    • TypeScript 2.0以降、strict null checkingが導入され、nullおよびundefinedの型安全性が向上しました。
  8. TypeScript 3.xシリーズ(2018年 - 現在):
    • TypeScript 3.xシリーズでは、Tuple型、readonly修飾子、Unknown型、Optional Chaining、Nullish Coalescing Operatorなど、新しい機能が追加されました。
  9. ESNextの機能への追随(常時更新中):
    • TypeScriptはECMAScriptの進化に追随し、新しいJavaScriptの機能をサポートしています。

TypeScriptは、プロジェクトの規模が大きくなるにつれてその恩恵がより顕著に現れる言語であり、JavaScriptエコシステムで広く受け入れられています。


クラス 編集

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) {
    this.longitude = longitude;
    this.latitude = 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: { [key: string]: GeoCoord } = {
  "東京駅": new GeoCoord(139.7673068, 35.6809591),
  "シドニー・オペラハウス": new GeoCoord(151.215278, -33.856778),
  "グリニッジ天文台": new GeoCoord(-0.0014, 51.4778),
};

for (const prop in Sites) {
  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でのインターフェースとオブジェクトの使用例を示しています。

  1. MyInterface インターフェースは、idnameage の3つのプロパティを定義しています。
    • id プロパティは number 型で読み取り専用 (readonly) です。
    • name プロパティは string 型です。
    • age プロパティは number 型で、省略可能なオプションプロパティです。
  2. myObject 定数は、MyInterface インターフェースに準拠したオブジェクトです。
    • idname プロパティは指定されており、age プロパティは省略されています。
    • id プロパティは読み取り専用なので、オブジェクトが作成された後に再代入することはできません。
  3. コメントされた行 myObject.id = 2; は、id プロパティが読み取り専用であるため、再代入しようとするとエラーが発生します。
  4. myObject.age = 30; のように、オブジェクトのプロパティ age に値を追加することはできます。age はオプションプロパティであるため、省略することもできますが、存在する場合は number 型である必要があります。

これにより、TypeScriptでは型安全性が向上し、コードの信頼性と保守性が向上します。

列挙型 編集

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つの値(RedGreenBlue)を持たせています。関数printColorは、Color型の引数を受け取り、その値が何であるかに応じて、対応する色の文字列をコンソールに出力します。

このコードには default 節がないため、すべての enum Color のメンバーに対して switch 文での処理が定義されていないと、TypeScript コンパイラがエラーを出力します。つまり、 enum Color に新しいメンバーを追加するときは、すべての場合分けを考慮して switch 文を更新する必要があります。

そのため、このコードでは網羅性が担保されており、メンバーの追加などの変更があった場合にもコンパイルエラーで指摘されるので、開発者が見落としを防ぐことができます。

JavaScriptには列挙型の概念がないため、同じような機能を実現するためには、オブジェクトや配列を使用することが一般的です。例えば、以下のようなconstオブジェクトを定義して列挙型の代わりに使用することができます。

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とフロントエンド・フレームワーク 編集

TypeScriptを活用したフロントエンド開発には、様々なフレームワークが存在し、それぞれの特性によってプロジェクトの選択が可能です。特に、仮想DOMに基づくフレームワークや仮想DOMを使わないアプローチがあり、それぞれ一長一短があります。

仮想DOM 編集

仮想DOM(Virtual DOM)は、ウェブアプリケーションの効率的なUI更新を実現するための概念です。通常、ウェブブラウザ上でのUIの変更はDOM(Document Object Model)と呼ばれる階層構造を持つ要素を直接変更することで行われます。しかし、これには効率上の課題が存在します。

仮想DOMは、UIの変更をより効率的に行うために導入された手法で、以下のような仕組みを採用しています:

仮想DOMの構築
変更前のUI状態と変更後のUI状態の差分を把握するために、現在のDOMツリーの簡易的なコピーである仮想DOMが構築されます。
変更の検出
変更前と変更後の仮想DOMを比較して、変更がある部分を検出します。この過程で効率的に変更点を見つけることができます。
差分の適用
変更点が特定されたら、それに基づいて実際のDOMツリーに対する変更が行われます。ただし、これは必要な最小限の変更のみが行われるため、全体の再描画が行われるよりも効率的です。
再描画
実際のDOMへの変更が行われた後、ブラウザが必要な部分だけを再描画します。この際、再描画対象が限定されるため、全体のページの再描画よりも高速です。

仮想DOMに基づくフレームワーク 編集

React.js + TypeScript: 効率的なUI構築と型安全性の融合 編集

React.jsはMeta(旧Facebook)によって開発されたUI構築のためのライブラリであり、TypeScriptとの組み合わせにより型安全性が向上します。仮想DOMを利用することで、効率的で柔軟なUI更新が可能であり、大規模なアプリケーションにも適しています。

主な特徴:

型安全性の向上
TypeScriptとの統合により、静的な型チェックが可能となり、開発者はコードの安全性を確保できます。型の恩恵を受けながら開発を進めることができます。
仮想DOMによる効率的なUI更新
仮想DOMを活用することで、変更がある部分のみを効率的に更新することができます。これにより、UIの更新プロセスが迅速であり、ユーザーエクスペリエンスが向上します。
大規模なアプリケーションに適したアーキテクチャ
React.jsはコンポーネントベースのアーキテクチャを採用しており、これにより大規模なアプリケーションの構築や管理が容易になります。

React.js + TypeScriptの組み合わせは、型安全性と効率的なUI更新の両方を追求する現代のフロントエンド開発において非常に重要な選択肢となっています。

Angular: 大規模で型安全なアプリケーション構築 編集

AngularはGoogleによって開発され、大規模で複雑なアプリケーションの構築に適しています。元々TypeScriptで記述されており、強力な型システムを活かした開発が可能です。

主な特徴:

大規模アプリケーション向けのアーキテクチャ
Angularはモジュール、サービス、ディレクティブ、コンポーネントなどのコンセプトを採用しており、これらを組み合わせて大規模なアプリケーションを構築しやすくしています。
強力な型システム
TypeScriptを採用しているため、開発者は静的な型付けを利用してコードの安全性を確保できます。これにより、エディタの補完機能やエラーチェックが強化されます。
豊富な機能セット
Angularはルーティング、フォーム処理、HTTPクライアントなど、標準で豊富な機能を提供しており、これにより開発者はアプリケーションの開発において効率的に作業できます。

Angularはこれらの特徴を組み合わせ、大規模で複雑なアプリケーションの開発をサポートしています。型安全性と豊富な機能セットにより、堅牢でメンテナンス性の高いアプリケーションを構築することが可能です。

Vue.js + TypeScript: 柔軟性と型安全性の調和 編集

Vue.jsはEvan Youによって開発され、シンプルで柔軟な構文を提供するライブラリです。Vue.jsにTypeScriptを組み込むことで、プロジェクトの可読性や保守性が向上します。

主な特徴:

柔軟でシンプルな構文
Vue.jsは直感的で柔軟な構文を提供し、コンポーネント指向のアーキテクチャに基づいています。これにより、初心者から経験豊富な開発者までが手軽に利用できます。
TypeScript統合による型安全性
TypeScriptを導入することで、開発者は静的な型付けによる安全なコーディングを享受できます。タイプミスやエラーを早期に検知し、可読性の高いコードを実現します。
単一ファイルコンポーネント
Vue.jsではHTML、JavaScript、CSSを1つのファイルにまとめた単一ファイルコンポーネントが使われます。これにより、コンポーネントごとに必要なものが一元管理され、開発プロセスがスムーズになります。

Vue.js + TypeScriptの組み合わせは、柔軟性と型安全性のベストなバランスを提供します。豊富なエコシステムと優れたドキュメントにより、開発者は生産性を維持しながら高品質なアプリケーションを構築できます。

仮想DOMを使わないフレームワーク 編集

Svelte: 仮想DOMを使わない新しいアプローチ 編集

Svelteは仮想DOMを使わず、ビルド時にコンパイルされる手法を採用しています。この特異なアプローチにより、ランタイムのオーバーヘッドが極めて少なく、最終的なアプリケーションのサイズを著しく小さく保つことができます。

主な特徴:

ランタイム効率
コンポーネントはビルド時にフレームワークのコードに変換され、ランタイムには最適化されたバニラJavaScriptが残ります。これにより、実行時のオーバーヘッドが最小限に抑えられます。
サイズの最適化
Svelteは変更の必要な部分だけをコンパイルし、不要なライブラリやフレームワークの追加を排除します。結果として、最終的なアプリケーションのサイズが非常に小さくなります。
TypeScript統合
SvelteはTypeScriptとも統合が可能で、開発者は型安全性を確保しつつ、効率的でコンパクトなアプリケーションを構築できます。

このアプローチにより、Svelteは現代のフロントエンド開発において、軽量で効率的な選択肢として注目を浴びています。

Alpine.js: 軽量かつ直感的なUI制御 編集

Alpine.jsはJavaScriptとHTMLの標準的な属性を利用し、UIを制御するための軽量なライブラリです。仮想DOMを使用せず、直感的でシンプルな構文を提供しています。

主な特徴:

軽量性
Alpine.jsは小さなサイズであり、他の大規模なフレームワークやライブラリを必要としません。これにより、アプリケーションのファイルサイズを最小限に抑えます。
直感的な構文
HTMLの標準的な属性を使用してUIを制御するため、開発者は追加の学習コストなしに簡潔で直感的なコードを書くことができます。
シンプルなプロジェクトに適している
仮想DOMを使用せず、コンパクトな構文がアプリケーションのシンプルなプロジェクトに適しています。冗長なコードや複雑な構造を排除し、開発プロセスを簡素化します。

Alpine.jsはこれらの特性により、小規模なプロジェクトや簡潔なUIの実装において優れた選択肢となっています。

Hyperapp: 軽量で効率的な仮想DOMを使わないフレームワーク 編集

Hyperappは小規模なフレームワークで、特筆すべきは仮想DOMを使用しない点です。基本的な機能を提供しながらも、軽量で効率的なアプリケーションの開発が可能です。

主な特徴:

軽量性
Hyperappは小さなサイズであり、必要な機能に焦点を当てています。これにより、アプリケーションのファイルサイズを最小限に抑えます。
効率的なアプリケーション
仮想DOMを使わないことで、ランタイムのオーバーヘッドを削減し、アプリケーションのパフォーマンスを向上させます。簡潔なコードで効率的なアプリケーションを構築できます。
自由度の向上
仮想DOMを使わないアプローチにより、開発者は直接DOMに対して操作を行うことができ、アプリケーションの挙動を完全に制御できます。

これらの特徴により、Hyperappは小規模なプロジェクトや軽量なアプリケーションの開発に適しています。仮想DOMを使わないことで得られる自由度は、柔軟で効率的なフロントエンド開発に貢献しています。

仮想DOMでないとコンポーネント化は出来ないのか? = 編集

仮想DOMを使用しない場合でもコンポーネント化は可能です。コンポーネント化は、UIや機能を独立した部品として分割し、再利用性や保守性を向上させる開発手法です。仮想DOMはこの手法を実現するための一つのアプローチですが、他のアプローチも存在します。

例えば、Vue.jsは仮想DOMを採用していますが、Svelteは仮想DOMを使わずにコンポーネント化を実現しています。Svelteでは、ビルド時にコンポーネントがフレームワークによって最適化され、効率的なランタイムが生成されます。

コンポーネント化は、仮想DOMがなくても、適切なツールやライブラリを使用することで実現可能です。 ただし、仮想DOMを使用しない場合、手動でDOMの変更や再描画を管理する必要があり、その分コードの複雑性が増す可能性があります。選択はプロジェクトの要件や開発者の好みに依存するため、慎重に検討することが重要です。

その他のフロントエンドフレームワーク 編集

他にも様々なフロントエンドフレームワークが存在します。以下はいくつかの注目すべきフレームワークです。

Next.js
React.jsベースのフレームワークで、サーバーサイドレンダリングや静的サイト生成などの機能を提供しています。React.jsの強力な機能に加え、SEO向上やパフォーマンス最適化が期待できます。
Nuxt.js
Vue.jsベースのフレームワークで、Next.jsにインスパイアされています。Vueのシンプルな構文と、サーバーサイドレンダリング、ルーティングの自動生成などを組み合わせています。
Gatsby
React.jsを利用した静的サイトジェネレーターで、高速かつSEOフレンドリーなウェブサイトを構築できます。GraphQLを使用してデータのクエリが可能です。
Sapper (SvelteKit)
Svelteフレームワークの一部で、サーバーサイドレンダリングやルーティングの機能を提供します。SvelteKitとして進化しています。
Quasar Framework
Vue.jsベースのフレームワークで、モバイルアプリケーション、デスクトップアプリケーション、ウェブアプリケーションなど、異なるプラットフォーム向けのアプリケーションを効率的に構築できます。

これらのフレームワークはそれぞれ特有の特徴や用途に合わせて設計されており、プロジェクトのニーズや開発者の好みによって選択されることがあります。選択肢を検討する際には、ドキュメンテーションやコミュニティの活発さ、過去の実績なども考慮すると良いでしょう。

TypeScriptとバックエンド開発 編集

TypeScriptは、JavaScriptのスーパーセットであり、静的型付けをサポートするプログラミング言語です。TypeScriptは主にフロントエンド開発において人気がありますが、バックエンド開発にも利用されています。以下は、TypeScriptを使用したバックエンド開発においてExpress、およびNestJSとの関連性についての簡単な説明です。

TypeScriptとExpress 編集

ExpressはNode.jsのWebアプリケーションフレームワークであり、シンプルで柔軟な構造を提供します。ExpressアプリケーションをTypeScriptで書くことで、より安全かつ保守しやすいコードを実現できます。

// TypeScriptで書かれたExpressの例
import express from 'express';

const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello, Express with TypeScript!');
});

app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});

TypeScriptとNestJS 編集

NestJSは、エレガントで効果的なNode.jsフレームワークであり、Angularの影響を受けています。NestJSは、TypeScriptをサポートし、デコレータやモジュールのシステムを使用して、コードの構造を明確にし、開発を容易にします。

// TypeScriptで書かれたNestJSの例
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

これらの例は、TypeScriptを使用してExpress、およびNestJSでバックエンドを開発するための基本的な構造を示しています。各フレームワークやライブラリは異なる特性を持っていますが、TypeScriptを組み合わせることで、コードの品質や保守性を向上させることができます。

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のレベルで出来ません。