インストール

npmでインストールします。

$ npm install -g typescript

インストールできてるか確認。

$ tsc -v
Version 3.6.4

「-bash: tsc: command not found」と出てパスが通っていなかったら通す。

export PATH=$PATH:/usr/local/Cellar/node/8.1.3/lib/node_modules/typescript/bin:$PATH

プロジェクトディレクトリに移動して初期設定をする。

$ cd Project
$ tsc --init

簡単なファイルを作成してみましょう。

test.ts

let message = 'こんにちは!';
console.log(message);

tsファイルはそのままではブラウザで認識しないのでコンパイルします。

$ tsc test.ts

test.jsが新しく作成されていれば成功です。

ファイルを更新する度に毎回コマンドを実行するのは大変なので、次のコマンドを実行します。

$ tsc -b --watch

これでファイルを更新する度に自動的にビルドが実行されます。

VSCodeを使用している場合は、Cmd + Shift + bでビルドが実行できます。

型の基本

TypeScriptの特徴として型を明示的に指定することです。
よく使用する型としては次のものがあります。

number 数値
string 文字列
boolean 真偽値
array 配列
object オブジェクト
any なんでも入る
void 値を返さない関数等に使用
null, undefined 空の値

型の指定は変数名の後に:(コロン)を付けてその後に型名(アノテーション)を付けます。

let message :string = 'こんにちは';

たとえば数値型(number)で宣言した型に文字列を入れようとするとエラーになります。
VSCodeだとリアルタイムに注意してくれます。

配列

基本変数名の後に型名を指定するだけなのでそれほど難しいことはないですが、配列はちょっと書き方で迷いますよね。
これは、型名の後にブラケット([])を付けます。

let numbers1: number[] = [ 1, 2, 3 ];
let numbers2: Array<number> = [ 1, 2, 3 ];

配列と似たような型でtuple型というのがあります。これは固定数で複数の型を指定することができます。
例えば入れられる変数を「数値」「文字列」「数値」の順で制限したい場合次のようになります。

let list: [number, string, number] = [
	1, 'hoge', 2
];

オブジェクト

オブジェクトの場合は次のようになります。

let user: object = {
	id: 1,
	name: '山田太郎',
	age: 28
};

しかしこれだと、オブジェクトの中の型推論ができません。
TypeScriptにはインターフェイスという機能があり、次のようにすると型推論ができるようになります。

interface User {
	id: number
	name: string
	age: number
};

typeを使用する方法もあります。

type User = {
	id: number
	name: string
	age: number
};

使い方はどちらも同じです。

let user: User = {
	id: 1,
	name: '山田太郎',
	age: 28
}

オブジェクトの場合、プロパティがない場合もあります。
その場合、変数の後に?を付けます。

type User = {
	id: number
	name: string
	age?: number
};
	
let users: User[] = [
	{
		id: 1,
		name: '山田太郎',
		age: 28
	},{
		id: 2,
		name: '田中一郎'
	}
]

複数の型指定(Union Types)

JavaScriptだと何もない値の場合、nullやundefinedになりますが、string型で宣言していた場合、文字列しか入れることができないのでエラーになります。その場合、Union Typesという指定方法で複数の型を使用できるようになります。

let message : string | null = 'こんにちは';
message = null; // nullも入れることができる

関数

関数は引数の後に型名を記述します。

function sum(num1: number, num2: number): string {
	const sum: number = num1 + num2;
	return `${num1}+${num2}は、${sum}です。`;
}

sum(3,5) // 3+5は、8です。

クラス

TypeScriptのクラスメンバーは修飾子(public・private・protected)を付与できる。

class Calc {
	private num1: number;
	private num2: number;
	constructor (num1: number, num2: number) {
		this.num1 = num1;
		this.num2 = num2;
	}

	public sum(): string {
		const sum: number = this.num1 + this.num2;
		return `${this.num1}+${this.num2}は、${sum}です。`;
	}
}

const calc = new Calc(5,6);
calc.sum(); // 5+6は、11です。

ゲッター/セッター

クラスプロパティを操作するのにゲッター/セッターメソッドを作ることはよくありますが、TypeScriptではget/setアクセサという機能があります。

class Test {
	private _type: string;

	constructor(type: string) {
		this._type = type;
	}

	set type(type: string) {
		this._type = type;
	}

	get type(): string {
		return this._type;
	}
}

const test = new Test('test');
test.type = 'test2';
test.type; // test2

列挙型

列挙型は複数の定数をひとまとめすることができる変数です。
次のように何も代入しない場合は0からのインクリメントされた値が入ります。

enum Role {
	Admin,
	Master,
	Editor,
	User
};
Role.Editor; // 2

ジェネリクス

ジェネリクスは関数やクラスの定義時にはまだ型が決まっていなくて、使用時に型を指定したいときに使用できる機能です。
たとえば関数の引数を使用時に決めたい場合は次のようになります。

function genericsTest<T>(type: T) :T {
	return type;
}
genericsTest<string>('test');

<T>の部分はエイリアスになり任意の文字列を使用することができますが、Typeの頭文字のT、KeyのK、UnknownのU、ElementのEなどが使用されることが多いようです。

複数のジェネリクス

複数のジェネリクスを使用する場合は「,」で区切って記述します。

function genericsTest<T, K>(type: T, key:K) :string {
	return `${type} + ${key}`;
}
genericsTest<string, number>('test', 100);

インターフェイスのジェネリクス

ジェネリクスはインターフェイスで使うことが多いかもしれません。

interface GenericsTest<T> {
	value: T
	title: string
}

const test1: GenericsTest<number> = {
	value: 100,
	title: "ジェネリクステスト"
}

const test2: GenericsTest<string> = {
	value: '100',
	title: "ジェネリクステスト"
}

実践TypeScript ~ BFFとNext.js&Nuxt.jsの型定義~