今どきはよく「JavaScriptじゃなくてTypeScriptを使うべき」みたいな話を聞くのですが、ネット上のどのTypeScript入門も、JavaScriptを知っている前提で話が進みます。以前、友達に「JavaScript知らないんだけど、それをすっ飛ばしてTypeScriptを学ぶ方法はないの?」と訊いたところ、「素直にJavaScriptをしてから、TypeScriptしようね。」という回答が帰ってきました。にゃーん。
しかし、これは正しい回答で、TypeScriptの公式サイトのLearning JavaScript and TypeScriptに以下のことが書かれています。
We frequently see the question “Should I learn JavaScript or TypeScript?“.
The answer is that you can’t learn TypeScript without learning JavaScript! TypeScript shares syntax and runtime behavior with JavaScript, so anything you learn about JavaScript is helping you learn TypeScript at the same time.
翻訳すると以下の通り。
『JavaScriptとTypeScriptのどちらを学ぶべきか』という質問をよく目にします。
答えは、JavaScriptを学ばなければTypeScriptを学ぶことはできないということです。 TypeScriptはJavaScriptと構文と実行時の動作を共有するため、JavaScriptについて学んだことはすべて、TypeScriptを同時に学ぶのに役立ちます。
なるほど、JavaScriptなくして、TypeScriptは語れないということですね。ただ、JavaScriptを学んで、TypeScriptを学ぶというのは、道のりが長い気がします。というわけで、JavaScriptを学びながら、TypeScriptを学べる「JavaScriptを知らないためのTypeScript入門」を書いてみました。
体系的に学びたい方へ
JavaScriptもTypeScriptもだいたい分かるにょん、という方や、この記事を読み終えた方、もしくは
このような方は、[TypeScriptの公式サイト](https://www.typescriptlang.org/)の[The TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html)(英語)を読むことをおすすめします。TSの体系的な資料見たことないな…
— へだる (@hedalu244) November 13, 2020
typeとinterfaceでなんとかなってしまうので、それ以外は必要に応じて毎回調べてて見落とし機能が多そう
事前に知っておくべきこと
この記事はMDN web docsのJavaScriptガイドに沿って話を進めていきます。このガイドは事前に知っておくべきことに書かれている予備知識を持っていることを前提としています。
本記事では読み飛ばしてもいい章があります。例えば、今は正規表現を使わないことが明確である場合は8章を読み飛ばしても問題ありません。読み飛ばして分からない場合は前の章に戻ってみましょう。
用語説明
まず用語の説明をします。記事に出てくるキーワードや、よく見かけるキーワードについて簡単な説明を書きました。記事で分からないキーワードが出てきたら、ここに戻って見ましょう。
HTML・CSS・JavaScriptとは何か
JavaScriptを知らない方はそもそもHTMLとCSSとJavaScriptとは何なのかを知らない方かもしれません。
この記事では詳しくは説明しませんが、@shuntaro_tamuraさんの超絶初心者のためのフロント入門(HTML、CSS、JavaScript)を読めば簡単に理解できると思います。
ナンセンスな例えですが、家に例えると、
骨組みや柱がなどの「構造」がHTML、
壁紙や窓のデザインなどの「装飾」がCSS、
電気やガスのスイッチなどの「動的な処理」がJavaScript
ですね。
HTMLについてもっと詳しく知りたい方はMDN web docsのHTML: HyperText Markup Languageを読むことをおすすめします1。CSSについてもっと詳しく知りたい方はMDN web docsのCSS: カスケーディングスタイルシートを読むことをおすすめします。JavaScriptについてもっと詳しく知りたい方はMDN web docsのJavaScript とはを読むことをおすすめします。
TypeScriptとは何か
一言で言うと、JavaScriptを拡張して作られたプログラミング言語です2。
JavaScriptとTypeScriptの大きな違いは「型定義」ができるかできないかです。JavaScriptには変数に型がありませんが、TypeScriptには変数に型があります。変数に型を付けることができるので、ちょっとしたミスが起きにくくなります。
ちなみに、JavaScriptを拡張して作られたプログラミング言語は他にも色々あって、それらを総称してAltJS(Alternative JavaScript)と呼びます。
さきほどの例えの続きですが、今まで電気やガスのスイッチなどの「動的な処理」をJavaScriptでやっていたけれど、最近では代わりにそこをTypeScriptで処理することがあるという感じです。
TypeScriptの長所にもっと詳しく知りたい方は@SoraKumoさんのTypeScriptをお勧めしたい7つの理由を読むことをおすすめします。
その他の説明
DOM(Document Object Model)は一言でいうと、HTMLやXMLで書かれた文書などを木構造のオブジェクトで表現することで、文書をプログラムから操作・利用することを可能にする仕組みです。詳しくは説明しませんが、@takiyu713さんのDOMと仮想DOMについてを読めば簡単に理解できると思います。もっと詳しく知りたい方はMDN web docsのDOM の紹介を読むことをおすすめします。
Node.jsは一言でいうと、ブラウザ上という制限された環境でしか動けなかったJavaScriptを、PythonやRubyのようにパソコン上で動かせるようにしてくれるものです。詳しくは説明しませんが、@non_calさんのNode.jsとはなにか?なぜみんな使っているのか?を読めば簡単に理解できると思います。
npmは一言でいうと、Node.jsのモジュールを管理するツールです。詳しくは説明しませんが、@righteousさんの【初心者向け】NPMとpackage.jsonを概念的に理解するを読めば簡単に理解できると思います。
0章: 環境構築
JavaScriptはそのままブラウザ上で動きますが、TypeScriptはJavaScriptに変換してからでないと動きません。
そこでTypeScriptコンパイラを使って、TypeScriptをJavaScriptに変換します。
今回はTypeScriptを中心に学ぶので、環境開発は最低限で行います。
- Node.jsをインストール
- Node.jsの公式サイトからLTSをダウンロードし、インストールします。
- npmはNode.jsと一緒にインストールされます。
- TypeScriptコンパイラをインストール
- コマンドプロンプトやターミナルなどを実行し、下記のコマンドを実行してください。
-
npm install -g typescript
(もしくはsudo npm install -g typescript
)でTypeScriptコンパイラをインストールします。
- インストールの確認
-
tsc -v
を実行し、バージョンが表示されればインストールは完了です。
-
以下は、実行例です3。
$ node -v
v12.19.0
$ npm -v
6.14.8
$ npm install -g typescript
...
+ typescript@4.1.2
added 1 package from 1 contributor in 23.883s
$ tsc -v
Version 4.1.2
TypeScriptの環境構築についてもっと詳しく知りたい方は@ochiochiさんのTypeScriptチュートリアル① -環境構築編-を読むことをおすすめします。
1章: Hello, world!
実際にTypeScrptのプログラムを書いて、コンパイルして、実行してみましょう。
さて、Hello, world!
を表示させるという一億番煎じ4のプログラムですが、次のソースコードをお好きなエディタ5で書いて、hello.ts
という名前で保存してください。
console.log('Hello, world!');
そしてコマンドプロンプトもしくはターミナルで、下記のコマンドを実行してください3。
$ tsc ./hello.ts
このtsc
コマンドがTypeScriptコンパイラです。うまくコンパイルできると、結果としてhello.js
というファイルができます。ここでは簡単にNode.jsで実行してみましょう。次のコマンドを入力してください3。
$ node hello.js
実行すると、コマンドプロンプトもしくはターミナルでHello, world!
が表示されます。
$ tsc ./hello.ts
$ node hello.js
Hello, world!
2章: 文法とデータ型
この章からは、はじめにMDN web docsのJavaScriptガイドを読み、次にTypeScriptではJavaScriptとどう違うかを説明していく形式で進めていきます。「JavaScriptではこのように書きます。では、TypeScriptではどうしょう。」といった感じですね。
さて、この章では最初に文法とデータ型を読んで、JavaScriptの知識を付けましょう。
この章ではTypeScriptは以下の点でJavaScriptと違いが見られます。
- TypeScriptはJavaScriptと違って、変数、定数、関数、引数などの後ろに
: 型名
を指定することで型を宣言することができます。これを型アノテーション(Type Annotation)と言います。型に一致しない代入や参照が行われるとコンパイルエラーが発生します。
型アノテーション
TypeScriptでは型アノテーションでプリミティブ型を指定することができます。
let v_bool: boolean = true;
let v_null: null = null;
let v_undef: undefined = undefined;
let v_num: number = 123;
let v_bigint: bigint = 11451481093189319194545072136436489464n;
let v_str: string = "Hello, world!";
ただし、ターゲットがES2020未満の場合、bigintリテラルは使用できないので気をつけてください。
なお、配列やオブジェクトの型は以下のように指定できます。
let coffees: string[] = ['French Roast', 'Colombian', 'Kona'];
var car: object = { myCar: 'Saturn', getCar: 'Honda', special: 'Toyota' };
実際に型に一致しない代入や参照が行われるとコンパイルエラーが発生するか確かめてみましょう。
var v_num: number = 123;
var v_str: string = 123; // ここでコンパイルエラー!
型推論
JavaScriptでは以下のように書くことができます。詳しくは説明しませんが、MDN web docsのデータ型の変換を読めば簡単に理解できると思います。
var answer = 42;
answer = 'Thanks for all the fish...';
ただ、これをTypeScriptとして書くと次のようなコンパイルエラーが出ます。
$ tsc test.ts
test.ts:2:1 - error TS2322: Type 'string' is not assignable to type 'number'.
2 answer = 'Thanks for all the fish...';
^^^^^^
Found 1 error.
TypeScriptは、いくつかの簡単なルールに基づいて変数の型を推論(およびチェック)します。これを型推論といいます。変数の型は、定義によって推論されます。つまり、var answer = 42;
はvar answer: number = 42;
と同じで、answer
の型はnumber
なのです。型推論についてもっと詳しく知りたい方は@uhyoさんのTypeScriptの型推論詳説を読むことをおすすめします。
このエラーを回避する方法として、以下の2つの方法があります。
1つ目に、|
を使用することで、複数の型を指定する方法があります。
string または number の型を示す場合は number | string
とします。
詳しくは12章の共同型で説明します。
var answer: number | string = 42;
answer = 'Thanks for all the fish...';
もう一つの方法は、any
を使用することで、プリミティブを含む任意の型を許容することです。
var answer: any = 42;
answer = 'Thanks for all the fish...';
数値と '+' 演算子
数値と文字列を+
演算子で結合する式では、TypeScriptは数値を文字列に変換します6。以下の式を見てみましょう。
var x = '答えは ' + 42; // "答えは 42"
var y = 42 + ' が答え'; // "42 が答え"
それ以外の演算子がある式では、型が違うため、TypeScriptはコンパイルエラーになります。
'37' - 7 // ここでコンパイルエラー!(JavaScriptだと30になります。)
'37' + 7 // "377"
3章: 制御フローとエラー処理
if文などの制御フローやtry...catch構文はJavaScriptと同じです。MDN web docsの制御フローとエラー処理を読めば簡単に理解できると思います。
4章: ループと反復処理
ループ文はJavaScriptと同じです。MDN web docsのループと反復処理を読めば簡単に理解できると思います。
5章: 関数
この章では最初に関数を読んで、JavaScriptの知識を付けましょう。
この章ではTypeScriptは以下の点でJavaScriptと違いが見られます。
- 関数の返り値の型を型アノテーションで指定できます。
関数の返り値の型指定
例えば、次のコードはsquare
という名前の簡単な関数を定義します:
function square(x: number): number {
return x * x;
}
例えば、関数式では次のように定義できます:
const square = function(x: number): number { return x * x; };
var x = square(4); // x の値は 16 となる
もちろん関数式に名前をつけることもできます:
const factorial = function fac(n: number): number { return n < 2 ? 1 : n * fac(n - 1); };
console.log(factorial(3));
(引数名:型, 引数名:型 ...) => 戻り値
と書くことで関数を型指定することができます。第1引数のfはnumberの型の引数を一つ取り、numberの型を返す関数なので、: (x: number) => number
で型指定することができます。次の例ではmap
関数を定義し、第1引数に関数を取り、第2引数に配列を取ります:
function map(f: (x: number) => number, a: number[]) {
let result = []; // 新しい配列を作成
let i: number; // 変数の宣言
for (i = 0; i != a.length; i++)
result[i] = f(a[i]);
return result;
}
下記のコードでは、この関数は関数式で定義された関数を受け取って、2つ目の引数で受け取った配列の各要素に対して実行しています。
function map(f: (x: number) => number, a: number[]) {
let result = []; // 新しい配列を作成
let i: number; // 変数の宣言
for (i = 0; i != a.length; i++)
result[i] = f(a[i]);
return result;
}
var f = function (x: number): number {
return x * x * x;
};
let numbers = [0, 1, 2, 5, 10];
let cube = map(f, numbers);
console.log(cube);
これは[0, 1, 8, 125, 1000]
を返します。
6章: 式と演算子
式と演算子はJavaScriptと同じです。MDN web docsの式と演算子を読めば簡単に理解できると思います。
7章: テキスト処理
テキスト処理はJavaScriptと同じです。MDN web docsのテキスト処理を読めば簡単に理解できると思います。
8章: 正規表現
正規表現はJavaScriptと同じです。MDN web docsの正規表現を読めば簡単に理解できると思います。
正規表現が意図したとおりに動くか試したいときは、regex101.comというとても便利なサイトがあるので、ぜひ試してみてください。
9章: インデックス付きコレクション
この章では最初にインデックス付きコレクションを読んで、JavaScriptの知識を付けましょう。
配列の型アノテーション
配列の型アノテーションは以下のように、変数を宣言するときに配列の要素の型の後に[]
を付けます。
let emp: string[] = []
emp[0] = 'Casey Jones'
emp[1] = 'Phil Lesh'
emp[2] = 'August West'
また、Array<型>
と指定して書くことも可能です。
let emp: Array<string> = []
emp[0] = 'Casey Jones'
emp[1] = 'Phil Lesh'
emp[2] = 'August West'
2次元配列の型アノテーション
2次元の配列の場合は[][]
と、[]
を二つ書けばいいです。
var table: number[][] = new Array();
for (let i = 0; i < 9; i++) {
table[i] = new Array();
for (let j = 0; j < 9; j++) {
table[i][j] = (i + 1) * (j + 1);
}
}
10章: キー付きコレクション
この章では最初にキー付きコレクションを読んで、JavaScriptの知識を付けましょう。
Mapの型アノテーション
Mapオブジェクトの型アノテーションは以下のように、Map<キーの型, 値の型>
と書きます。
let sayings: Map<string, string> = new Map();
sayings.set('dog', 'woof');
sayings.set('cat', 'meow');
sayings.set('elephant', 'toot');
このファイルをコンパイルする際はtsc ./sayings.ts --lib es6
としてください。
Hashの型アノテーション
Hashオブジェクトの型アノテーションは以下のように、Map<要素の型>
と書きます。
let mySet: Set<number | string> = new Set();
mySet.add(1);
mySet.add('some text');
mySet.add('foo');
11章: オブジェクトでの作業
この章では最初にオブジェクトでの作業を読んで、JavaScriptの知識を付けましょう。
オブジェクトの型アノテーションは以下のように、object
で指定できます。
var myCar: object = {
make: 'Ford',
model: 'Mustang',
year: 1969
};
TypeScriptにはObject
というものもあり、var myCar: Object = ...
と書いてもコンパイルが通ります。6 TypeScriptのObject型とobject型は同じ……と思うじゃん?ところがどっこい、そうではありません。詳しくは説明しませんが、@suinさんの書いたこの記事を読めば簡単に理解できると思います。
12章: 型の定義
この章では、引き続きMDN web docsのオブジェクトでの作業に沿って話を進めつつ、TypeScriptの公式サイトのTypeScript for JavaScript Programmersに書かれているような説明を加えていきます。
interface
TypeScriptでは、以下のようにinterface
キーワードを使って、インターフェイスの宣言を使用して、オブジェクトの形状を明示的に記述することができます。
interface Car {
make: string;
model: string;
year: number;
}
次に、変数宣言の後に以下のように構文を使用して、JavaScriptオブジェクトがCar
インターフェイスの形状に準拠していることを宣言できます。
interface Car {
make: string;
model: string;
year: number;
}
var myCar: Car = {
make: 'Ford',
model: 'Mustang',
year: 1969
};
共同型
共同型を使えば、複数の型をひとまとめにすることができます。たとえば、ブール型をtrue
またはfalse
のいずれかとして記述できます。
type MyBool = true | false;
ところで、このMyBool
の型はboolean
です。これについてはここで説明しません。
とはいえ、MyBool
なんて型を実際に使うことはないでしょう。共同型のもっと一般的な使用例は、値が許可されている文字列または数値リテラルのセットを記述することです。
type OthelloColor = 'black' | 'white';
type OneDigit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
type Make = 'Ford' | 'Eagle' | 'Nissan' | 'Mazda';
13章: オブジェクトモデルの詳細
PromiseはJavaScriptと同じです。MDN web docsのオブジェクトモデルの詳細を読めば簡単に理解できると思います。
14章: Promiseを使う
PromiseはJavaScriptと同じです。MDN web docsのPromiseを使うを読めば簡単に理解できると思います。
15章: イテレーターとジェネレーター
イテレーターとジェネレーターはJavaScriptと同じです。MDN web docsのイテレーターとジェネレーターを読めば簡単に理解できると思います。
16章: メタプログラミング
メタプログラミングはJavaScriptと同じです。MDN web docsのメタプログラミングを読めば簡単に理解できると思います。
17章: インターフェイス
これはJavaScriptにはない機能です。他のプログラミング言語と同じで、中身の実装を持たずに、メンバーや型の定義だけ持つ機能のことです。
この章に関しては、The TypeScript HandbookのInterfaces(英語)を読めば簡単に理解できると思うので、説明しません。英語が読めない方は@murankさんのTypeScript Handbook を読む (3. Interfaces)を読むといいかもしれません。
また、@nogsonさんのTypescriptのinterfaceの使い方や、@t_t238さんの【TypeScript】インターフェースの使い方を読んでも簡単に理解できると思います。
18章: ジェネリクス
これもJavaScriptにはない機能です。ジェネリクスは実は前にやった<>
のことです。ジェネリクスは、実際に使われるまで型が決まらないときに、抽象的な型(ジェネリック型)を使うことで、いろいろな型の値を与える関数などを作るときに使います。ジェネリクスは総称型と呼ばれることもあります。
この章に関しては、The TypeScript HandbookのGenerics(英語)を読めば簡単に理解できると思うので、説明しません。英語が読めない方は@murankさんのTypeScript Handbook を読む (6. Generics)を読むといいかもしれません。
19章: 列挙型
これもJavaScriptにはない機能です。この記事では詳しくは説明しませんが、The TypeScript HandbookのEnums(英語)を読めば簡単に理解できると思います。英語が読めない方は@murankさんのTypeScript Handbook を読む (7. Enums)を読むといいかもしれません。
実はTypeScriptでは列挙型はあまり使われません。代わりに共同型を使います。このことについてもっと詳しく知りたい方はTypeScriptのenumを使わないほうがいい理由を、Tree-shakingの観点で紹介しますや、[TypeScript] 列挙型は Union か enum か、または、さようなら、TypeScript enumを読むことをおすすめします。
20章: TypeScriptを実践する
TypeScript自体の説明は前の章で終わりです。この章では、TypeScriptを実際に使う際に参照するべき記事を紹介します。TypeScriptを学んでいる皆さんはおそらく何か目的を持っているはずですから、ここではその目的への橋渡しをしたいと思っています。
ここに書かれていない参考になる記事があったらコメント欄に書いてください。コメント歓迎します。
React + TypeScript
おそらく、ReactでTypeScriptする方が多いでしょうか。私もそのうちの一人です。
- @yonettyさんのTypeScriptでReactに入門するチュートリアル
- @makishyさんのReact + Redux + TypescriptでサンプルWebアプリ
- TypeScript Deep Dive 日本語版のReact
vue.js + TypeScript
布教用
JavaScriptを使っている人に向けてTypeScriptを勧めるときの記事です。
あとがき
お疲れ様でした!
ひとまず、これでこの記事は終わりです。この記事はごちゃごちゃとJavaScriptとTypeScriptを行ったり来たりしているので、整理したい方や、やった内容を忘れてしまった方もいらっしゃると思います。そんなときは上に方にある「体系的に学びたい方へ」で紹介した公式ドキュメントをお読みいただけるとスッキリすると思います。また、飛ばした章や読んでいないリンク先の記事(特に詳しく知りたい方用の記事1)は後でまた読んで見ると新たな知見を手に入れることができると思います。
この記事書いている人はJavaScriptとTypeScriptの言語の根っこから理解しているわけではないので、大きな誤解をしているかもしれません。(私自身がJavaScriptをすっ飛ばして、TypeScriptを勉強した身ですので…)くだらない間違いはコメントください。(みんなコメント書こうね。)あんまりにも間違いが多くて呆れた方はどうか代わりに正しい記事を書いてください。そしたら、この記事を消します。
-
この記事では「…にもっと詳しく知りたい方は…を読むことをおすすめします」という構文で紹介している記事はとても詳しく書いてあることがあるため、初心者向けではない可能性があることに留意してください。 ↩ ↩2
-
関西型言語が得意な方が次のようなことを言っていましたが、これは冗談です。
へえー、JavaとTypeScriptが合体して生まれたのがJavaScriptなんや。
— 無職やめ太郎(本名) (@Yametaro1983) December 19, 2020 -
コマンドの
$
(ドル記号)は打たないでください。$
(ドル記号)が頭に付く行は、それに続くコマンドを実行することを意味しています。このドル記号のことをコマンドプロンプト(コマンド入力が可能な状態)と呼びます。これは、使用するシェルやターミナルソフトウェア設定により変化しますが この記事では、$
で統一します。 ↩ ↩2 ↩3 -
「一億番煎じ」はこの前Qiitaで見かけて思わず笑ってしまった単語です。どうやらオタク特有の過剰表現らしいですが、
Hello, world!
を表示させるプログラムに関しては、わりと冗談抜きで一億番煎じですね。 ↩ -
2077年、SDGsを達成してから44年経ち、ようやく世界に平和が訪れると思われていた。しかし、世界中が高度に発達し、プログラミングが盛んに行われるようになってから、人々の中で「どのテキストエディタ(またはIDEを始めとしたツールなど)が一番良いか」というテーマの論争が過激化していった。最初はお互いを批判するだけの、小さな小競り合いのようなものだったが、次第に、腱鞘炎で病院へ行くと「君はEmacsじゃなくてVimを使っているのに不思議だねぇ」と医者に言われるようになったり、ニュースで国内の指定暴力団Vimmerが暴れまわるようになったり、終いにはvi原理主義者がテロを起こして、アメリカが核を飛ばす始末。国外では戦争が、国内でも内戦が発生した最悪な状態で、Emacs派の主人公は友達のcenti(nanoの後継の後継の後継)派と共に他の仲間を探して、荒れ果てた日本を縦断する――。Qiita記事なのでこれ以上書くと怒られるので書きませんが、誰かこういう感じのフィクション作品を書いてくれませんか?「JetBrainを使っているやつは頭もJetBrainだな」「お前は今、二つ間違えた。一つ目はそれが褒め言葉であること、二つ目はJetBrainじゃなくてJetBrainsだ、(銃声)」というやり取りとか、VSCoderに対して悪魔のスキンHot Dog Standで目を潰すとかそういうシーンが見たいです。もちろんお好きなエディタで書いていいですよ。 ↩