はじめてのTypeScript入門

TypeScriptを使いたいけど通常のJavaScriptとどんな違いがあるのかやJavaScriptとは全く異なる言語でまた一から勉強をしなければならないかと疑問に思っている人もいるかと思います。本文書では公式のTypeScriptのドキュメントを参考し入門者を対象としてTypeScriptの基本について説明を行っています。
本文書を読み終えるとTypeScriptの型注釈(Type Annotation)とInterfaceの基礎を理解することができます。
TypeScriptとは
TypeScriptはJavaScriptの型の設定を行う機能が追加されたプログラミング言語です。JavaScriptとは異なる言語ではなく型の設定に関すること以外のコードについては通常のJavaScriptと同様の構文を使って記述することができます。
型がなぜそんなに大事かと疑問に思う人も多いかと思います。JavaScriptでは型を事前に宣言することがないので誤った型のデータを関数に渡している場合(文字列を渡さないければならないのに数値を渡す)実行中にエラーであることがわかります。しかし、TypeScriptは型を宣言するだけではなく事前にコンパイルを行う必要があるので、型に問題がある場合はコードを動作させる前に問題を把握することができます。またエディターによってはコードの記述中にエラーメッセージで型に問題があることを教えてくれます。また関数であれば引数、戻り値の型を設定することができるので他のプログラマーがコードを見てもどのような値を与えてどのような値が戻ってくるのかを理解することができます。
TypeScriptを利用する目的はエラーの少ない品質の高いコードを効率よく記述することにあります。JavaScriptを勉強をはじめプログラムが動くことを目的にする場合はそれほど重要ではありません。しかし、対価をもらって行う仕事であれば品質が高ければ高いほどいいのは明白です。大規模なプロジェクトにプログラマーとして参加するためにはTypeScriptの理解は必須です。
TypeScriptのインストール
参考にするのはドキュメントのTypeScript in 5 minutesです。
nodeがインストールされている環境でnpmコマンドでグローバルにtypescriptのインストールを行います。
$ npm install -g typescript
最も簡単な例を使った動作確認
テストデータの作成
次にgreeter.tsファイルを作成し下記のコードを記述します。TypeScriptのファイルの拡張子はtsです。
function greeter(person) {
return "Hello, " + person;
}
let user = "Jane User";
document.body.textContent = greeter(user);
はじめてのコンパイル
greeter.tsファイルを作成後TypeScriptからJavaScriptファイルへの変換を行う必要があります。変換はtscコマンドを利用します。
$ tsc greeter.ts
実行が完了するとtscコマンドを実行したディレクトリ内にgreeter.jsファイルが作成されます。
function greeter(person) {
return "Hello, " + person;
}
var user = "Jane User";
document.body.textContent = greeter(user);

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script src="./greeter.js"></script>
</body>
</html>
Type Annotation(型注釈)の追加
次にgreeter関数のpersonに型注釈を追加します。stringと追加したことでgreeterには文字列が入ることが宣言され、文字列を渡さない場合はエラーとなります。
function greeter(person: string) {
return "Hello, " + person;
}
stringを追加してもこれまでのコードであればuserは文字列の”Jane User”なのでエラーが表示されることもなくtscコマンドは型注釈を追加する前と同様にコンパイルも完了します。
しかし、意図的にuserに配列を渡してtscコマンドでコンパイルを実行するとエラーが発生します。
let user = [0, 1, 2];
以下のように数値で構成された配列を入れることができないとエラー表示されています。
$ tsc greeter.ts
greeter.ts:7:37 - error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'string'.
7 document.body.textContent = greeter(user);
~~~~
Found 1 error.
エラーが出力されてもJavaScriptへの変換は完了しgreeter.jsファイルは作成されます。
作成されるgreeter.jsファイルをindex.htmlファイルのscriptタグで読み込むと画面には、Hello, 0,1,2と表示され実行できないわけではありません。

ここまでの動作で”TypeScriptはJavaScriptに変換しないと利用することができないこと“と“型注釈を設定することで誤った型のデータ挿入を未然に防ぐことができること”が確認できました。
Interface(インターフェイス)とは
TypeScriptのInterfaceはオブジェクトの形を決めるルールのようなものでオブジェクトのプロパティの名前と型を定義することができます。
Interfaceの最もシンプルな使い方
例えばPersonというInterfaceを作成します。
interface Person {
firstName: string;
lastName: string;
}
PersonはfirstNameとlastNameの2つのプロパティを持ち、どちらの型もstringを持ちます。
先程のgreeter.tsファイルのgreeter関数の引数をオブジェクトに変更し、そのオブジェクトの型注釈に作成したインターフェイスを利用することができます。
function greeter(person: Person) {
return "Hello, " + person.firstName + " " + person.lastName;
}
Interfaceを型注釈で指定するとgreeter関数を実行する際に挿入するオブジェクトはfirstNameとlastNameを持ちその型はstringである必要があります。
let user = { firstName: "Jane", lastName: "User" };
document.body.textContent = greeter(user);
ここまでのコードをまとめてコンパイルを実行するとこれまでと同様にindex.htmlでgreeter.jsファイルを読み込むと画面上にはHello Jane Userが表示されます。
interface Person {
firstName: string;
lastName: string;
}
function greeter(person: Person) {
return "Hello, " + person.firstName + " " + person.lastName;
}
let user = { firstName: "Jane", lastName: "User" };
document.body.textContent = greeter(user);
プロパティ名や値を変更してエラーを確認
もしfirstNameではなくFullNameにした場合にどのようなエラーになるか確認しておきましょう。
let user = { fullName: "Jane", lastName: "User" };
コンパイルを実行するとプロパティのfirstNameがないとエラーが表示されます。
$ tsc greeter.ts
greeter.ts:12:37 - error TS2345: Argument of type '{ fullName: string; lastName: string; }' is not assignable to parameter of type 'Person'.
Property 'firstName' is missing in type '{ fullName: string; lastName: string; }' but required in type 'Person'.
次にlastNameの値を数字にしてみましょう。
let user = { firstName: "Jane", lastName: 20 };
コンパイルを実行すると先程のプロパティ名を変更した時と異なるエラーが表示されます。値がnumberなのでstringではないというエラーになっています。
$ tsc greeter.ts
greeter.ts:13:37 - error TS2345: Argument of type '{ firstName: string; lastName: number; }' is not assignable to parameter of type 'Person'.
Types of property 'lastName' are incompatible.
Type 'number' is not assignable to type 'string'.
このようにInterfaceは設計図のような役割を持ちその設計図通りになっていない場合にはエラーが表示されます。
変数userを設定する場合にもInterfaceを利用することができます。
let user: Person = {
firstName: "John",
lastName: "Smith"
}
ClassにInterfaceを利用する
Classを作成する際にInterfaceを利用することができます。
作成したInterfaceを利用してClassを作成したい場合はimplementsを使って記述することができます。
Interfaceは先程設計図のような役割といったとおりInterfaceをimplementsしたクラスStudentはfirstNameとlastNameを持つ必要があります。
interface Person {
firstName: string;
lastName: string;
}
class Student implements Person {
public firstName: string;
public lastName: string;
}
// publicがなくてもOK
class Student implements Person {
firstName: string;
lastName: string;
}
プロパティがない場合
もしlastNameがない場合はコンパイル時にエラーが発生します。
class Student implements Person {
public firstName: string;
}
$ tsc greeter.ts
greeter.ts:20:7 - error TS2420: Class 'Student' incorrectly implements interface 'Person'.
Property 'lastName' is missing in type 'Student' but required in type 'Person
publicではなくprivateを使用した場合
publicではなくprivateを指定した場合も確認しておきましょう。
class Student implements Person {
private firstName: string;
public lastName: string;
}
以下のようにprivateに設定していることでエラーが発生しています。
$ tsc greeter.ts
greeter.ts:25:7 - error TS2420: Class 'Student' incorrectly implements interface 'Person'.
Property 'firstName' is private in type 'Student' but not in type 'Person'.
プロパティに”?”がついた場合(optional properties)
地域によっては名前にmiddleNameを使う場合もあります。その場合に備えmiddleNameを追加したInterfaceを作成します。追加した場合はInterface Personをimplementsする際にはプロパティにmiddleNameが必要となります。
interface Person {
firstName: string;
middleName: string;
lastName: string;
}
class Student implements Person {
firstName: string;
middleName: string;
lastName: string;
}
Property ‘middleName’ is missing in type ‘Student’ but required in type ‘Person’.のエラーが表示されます。

しかしmiddleNameを使わない地域によってはmiddleNameはオプションなので必要ではありません。必須ではない(オプション)プロパティに”?”をつけるとStudentクラスでmiddleNameがなくてもエラーになりません。
interface Person {
firstName: string;
middleName?: string;
lastName: string;
}
class Student implements Person {
firstName: string;
lastName: string;
}
Classを使ってgreeter.tsを作成する
最初は少し混乱してしまうかもしれませんがClassとInterfaceを利用してgreeter.tsを作成します。
class Studentを作成していますが、constructorでfirstNameとlastNameでpublicを設定しています。

interface Person {
firstName: string;
lastName: string;
}
class Student {
fullName: string;
constructor(
public firstName: string,
public middleInitial: string,
public lastName: string
) {
this.fullName = firstName + " " + middleInitial + " " + lastName;
}
}
function greeter(person: Person) {
return "Hello, " + person.firstName + " " + person.lastName;
}
let user = new Student("Jane", "M.", "User");
document.body.textContent = greeter(user);
index.htmlファイルでgreeter.jsを読み込むと画面にはHello, Jane Userが表示されます。
console.logを利用してStudentクラスから作成したuserオブジェクトの中身を見るとfistNameとlastNameなどを確認することができます。

シンプルなコードを利用してTypeScriptの型注釈とInterfaceとClassについての基本を確認することができました。