TypeScriptでHello Worldから基本文法まで
TypeScriptはMicorosoftによって開発されたオープンソースのプログラミング言語であり、JavascriptのSupersetである。要するにJavaScriptで書いたコードはTypeScriptとしても動作可能で、TypeScriptはJavaScriptを拡張した文法を提供する。
提供するものはType = 型であり、VS CodeなどIDEを使えば型間違えをプログラミング実行時ではなくコードの記述時に気付くことができ、より効率的にプログラミングを進める事ができる。
また、型を定めておくことにより、その型が提供するプロパティ、メソッドをIDEが候補として表示し、これも開発効率の向上につながる。
文法を覚える必要はあるが、一度覚えれば大規模プロジェクトはもちろんのこと、個人開発でも生産性の観点でもある程度向上するのではないかという期待をもって取り敢えずインストールから基本文法までをまとめていく。
TypeScriptでHello World
まずはTypeScriptをインストール
$ npm install -g typescript
$ tsc -v
Version 4.0.2
tsが拡張子なので、main.ts
というファイル名でファイルを作成する
let message = 'Hello World';
console.log(message);
これをJavaScriptファイルにコンパイルする。.ts
は省略可能である。
$ tsc main
するとmain.js
が同一ディレクトリに生成される。
let message = 'Hello World';
console.log(message);
node main.js
を叩けばターミナルにHello Worldが表示される。
ちなみに高級言語からより機械語に近い低水準な言語へ変換する作業をコンパイルと呼び、同水準な言語へ変換することをトランスコンパイルと呼び分けることもある。その意味ではTypeScriptはjsへの変換はトランスコンパイルであるが、トランスコンパイルもコンパイルの一種なので、文脈にもよるが単純にコンパイルと言っても問題ないだろう。
watch optionでファイルの変更を監視
$ tsc -w main.ts
あるいは
$ tsc --watch main.ts
と打つと、ファイルを監視し、変更の度にコンパイルをやり直してくれる。コンパイルが面倒な時は監視させよう。
TypeScriptの文法をざっくり理解
それではTypeScriptの文法を、ある程度解読できるぐらいのレベルまで学んでいきたい。
基本タイプ
TypeScriptにはnumber,string,booleanという基本タイプが3つあり、それぞれ以下のように宣言する。
let firstName: string = 'Tom';
let score: number = 10;
let isNew: boolean = true;
宣言した変数名の後にコロンを付け、その後に型を宣言する方式である。scoreはnumberなので、ここにstringを代入しようとするとエラーとなりコンパイルに失敗する。もっともコンパイルの前にIDEが波線でエラーを教えてくれるのでその前に気づくことができる。
サブタイプ
基本タイプはnull
とundefined
のサブタイプを持つ、すなわち
let score: number = 10;
score = null;
socre = undefined;
と記述することができる。
anyタイプ
型を定義しない場合はanyを書ける。文字通りなんでも型である。ただし型情報が抜け落ちるので結局JavaScriptと同じになってしまう。third-partyライブラリを使う場合などどの型が来るか分からない場合とかに使える。
let anyValue: any = 10;
anyValue = true; // 何でも入れられる
anyValue = 'Hello';
配列
配列は下記の好きな方の書き方ができる。
let list1: number[] = [1,2,3];
let list2: Array<number> = [1,2,3];
ここにlist1.push('hello')
など文字列を入力するとエラーとなる。
混合タイプで数が決まっている場合は以下のようにする
let list3: [string, number] = ['1', 2];
数は決まっていなくて、文字列か数値が入るという場合
let list4: Array<number | string> = [1, '2', 3];
list4.push('4');
list4.push(5);
console.log(list4);
Array<number | string>
はUnionといって型のマージを行う。number | string
は数値か文字列かという意味である。
type aliasによりショートカットを作成しておいて呼び出すという方法もある。
type NumString = number | string; // 後述のunion type参照
let list4: Array<NumString> = [1, '2', 3]; // Array<number | string>と同等
関数
関数宣言は引数の型と戻り値の型を宣言することができる。
function add(num1: number, num2: number): number {
return num1 + num2;
}
オブジェクト
オブジェクトの形はinterfaceにより一度定義しておく。この定義は慣例的に頭が大文字なようである。
interface Person {
firstName: string;
lastName: string;
middleName?: string; // optional
}
const tom: Person = {
firstName: 'tom',
lastName: 'yoshioka'
};
interfaceは拡張が可能。プロパティを追加したい場合はまずはextends
interface Student extends Person {
schoolYear: number;
}
const tommy: Student = {
firstName: 'tom',
lastName: 'yoshioka',
schoolYear: 3,
};
classを作成することも可能。
class PersonClass implements Person {
firstName: string; // interfaceで定義した内容は必ずClassとして実装する必要がある。
lastName: string;
fullName: string;
constructor(firstName: string, lastName: string) {
this.firstName = firstName;
this.lastName = lastName;
}
showFullName() { // メソッドやプロパティを追加する分には問題なし
console.log(`my name is ${this.firstName} ${this.lastName}`);
}
};
const me = new PersonClass('tom', 'Yoshioka');
me.showFullName(); // my name is tom Yoshioka
generic
型を実行時に決定して使いたい場合に使う文法。複数の型で動作する関数を作りたいときなどに有効である。
function getArrayLength<T>(array: Array<T>) : number {
return array.length;
}
const arrayLengthNum = getArrayLength<number>([1,2,3]);
const arrayLengthStr = getArrayLength<string>(['1','2','3','4']);
console.log(arrayLengthNum); // 3
console.log(arrayLengthStr); // 4
この場合、配列の長さを返す関数は定義時に型を決めると汎用性が狭まるため、実行時に決定する方が賢い方法である。
Tの文字は何でも良くUNKOとかでも良いが、慣例的にTと書いている。複数ある場合はT,Uと順に大文字を使っていく。
function getSecond<T, U>(arg1: T, arg2: U) : U {
return arg2;
}
const secondValue = getSecond<number, number>(1,2); // 2
const secondValue2 = getSecond(1,5); // 5, 自動で型推論されるため<number, number>は省略可能
enum
JavaScriptにはないenumを宣言できる。
enum Color {Red, Green, Blue};
let c: Color = Color.Green;
console.log(c); // 1
enumの初期値は変更が可能である。
enum Color {Red = 5, Green, Blue};
let c: Color = Color.Green;
console.log(c); // 6
multi type (union type)
あまりよろしくは無いが、3rd Partyのライブラリを使用するときなど、どちらの型で来るかが分からない時がある。そんな時はmulti typeで最低限のチェックを行う。
let multiType : number | boolean;
multiType = 20;
multiType = true;