Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
プロ生ちゃんと学ぶ! TypeScript入門(2)

プロ生ちゃんと学ぶ! TypeScript入門(2)

TypeScriptの基本のキ。JavaScriptをベースに「TypeScriptをつまみ食い」しよう!

2015年5月27日

TypeScriptの基本中の基本である「型」「クラス」「インターフェース」をプロ生ちゃんと学ぼう。「今、TypeScriptやって損しない?」という疑問・不安についても回答する。

暮井 慧(くれい けい) & きよくら
  • このエントリーをはてなブックマークに追加

きよくら ならみ

きよくら ならみ

大都会岡山の片隅でエンタープライズ向けのWebアプリケーションに携わっているソフトウェアエンジニア。

・Microsoft MVP for ASP.NET/IIS
・Twitter: @kiyokura
・Blog: http://kiyokura.hateblo.jp/

暮井 慧

暮井 慧

都内の公立高校に通う女子高生。部活は、情報処理研究会。プログラミング生放送のキャラクター「プロ生ちゃん」として活動中!

・Twitter: @pronama
・Website: http://pronama.jp/kei

「つまみ食い」で始めるTypeScript

 暮井 慧(以下、慧)  TypeScriptってたくさん機能や特徴があるよね。私に使いこなせるのかな? ちょっと不安な気もするんだけど……。

 きよくら(以下、き)  大丈夫! もちろん、TypeScriptの言語仕様を全て把握して使いこなすには、それなりの学習コストが必要になると思う。でもTypeScriptは、JavaScriptが分かる人なら使い始めることは難しくない。今まで通りのJavaScriptをベースにコードを書きながら、学んだ機能や使ってみたい機能を徐々に取り入れながらプログラミングできるんだ。

 慧  JavaScriptをベースに「TypeScriptをつまみ食い」できるって感じ?

 き  いい表現だね。まさにそんな感じだと思う。じゃあさっそく、基本的なところから「つまみ食い」していこう。

TypeScriptの「型」の基礎

 き  最初のポイントは、「型」かな。まずは「TypeScriptは静的型付けができるJavaScript」とだけ捉えて、使い始めてもいいかもしれない。

 き  まず、型の種類について説明しておくよ。TypeScriptでは、基本型には以下のものがある。これらは、変数や引数、戻り値などの型として、いろいろなところで使うことになる。

  • number
  • string
  • boolean

 き  その名の通り、それぞれ、数値文字列真偽値(truefalseを扱う型だね。

 慧  シンプルだね! 他の言語だとintとかdoubleとかいろいろあるけど、numberだけなんだね。

 き  これらを記述する場合は、前回も説明した通り、: 型名という形式の型アノテーションを用いる。

  • 変数宣言の場合はvar 変数名: 型名
  • 関数の場合はfunction 関数名 (引数名:引数の型) : 関数の戻りの型 {}

 例えば、こんな感じだね。

TypeScript
function playOmikuji(age : number, name: string ) : string {
  var kuji : string = '';
  if (age === 17) {
    kuji = "大吉";
  }else{
    kuji ="凶";
  }
  return name + "さんの運勢は" + kuji + "です";
}

var age : number = 17;
var name : string = "慧";

var unsei : string = playOmikuji(age,name);
リスト1 型アノテーションのいろいろな使い方パターン

 慧  ふむふむ、なるほど。シンプルで分かりやすいね。

どんな値でも格納できるany型

 慧  JavaScriptって、同じ変数に数字や文字列を格納できるよね? それってTypeScriptだとできないの?

 き  いい質問だね。TypeScriptには、どんな型の値でも格納できることを表す次の型がある。

  • any

 き  ただし、当然だけどany型を使うと、コンパイラーによる型チェックや型があることによるコード補完などの恩恵を受けることができない。

 慧  ふむふむ。一長一短ってやつだね!

TypeScript
var a : number;
a = 123;
a = "345"; // コンパイルエラーになる

var x : any;
x = 123;
x = "346"; // 問題なし
リスト2 TypeScriptでもany型にすると、型チェックされないので同じ変数に数字や文字列を格納できる

 慧  any型を使うときは、よく考えて使う必要があるね!

その他の型

 き  他にも型はいろいろある。「null型」と「undefined型」は、JavaScriptのそれらと同じと思ってもらって問題ない。「void型」は関数に戻り値が無いことを示すときに利用する。それから、いわゆる列挙型の「enum型」も利用できる。

 慧  他には?

 き  あとはオブジェクト型と分類される型がある。これには、クラスやインターフェースなどいろいろなものが含まれる。これらのうちいくつかは、この後個別に説明するよ。

「型推論」で型アノテーションの省略

 慧  型チェックがあるから安心なのは分かるんだけど、やっぱりJavaScriptよりコードが増えちゃうよね。これって何とかならないのかな?

 き  それに対する答えの一つは「型推論」かな。TypeScriptでは初期化や関数の戻り値など、文脈からその変数の型が何になるかを推測できるときは、型の宣言を省略できる。

 さっきのおみくじの関数は、型推論を使って次のように省略して書ける。

TypeScript
function playOmikuji(age : number, name: string ) {
  var kuji = "";
  if (age === 17) {
    kuji = "大吉";
  } else {
    kuji ="凶";
  }
  return name + "さんの運勢は" + kuji + "です";
}

var age = 17;
var name = "慧";

var unsei = playOmikuji(age, name); // unseiはstring型として解釈される
リスト3 型推論を使って型の宣言を省略(omikuji.ts)

 慧  これだと、ほとんどJavaScriptコードを書くのと変わらないね!

TypeScriptの「クラス」と「インターフェース」

 き  さて、もう少しだけ型に関する話題を続けよう。JavaScriptには無くてTypeScriptにあるものとして、「クラス」と「インターフェース」を紹介するよ。

クラス

 慧  JavaScriptにはクラスは無いんだよね?

 き  そうだね。JavaScriptはプロトタイプベースのプログラミング言語で、C#やJavaのようなクラスベースの言語とは異なり、いわゆる「クラス」は無い。TypeScriptではクラスベースを取り入れているので、C#やJavaに近い考え方でクラスを定義して利用できるんだ。例えば、こんな感じかな。

TypeScript
class Hello {
  // メンバー変数
  public name: string;
  private _age: number;

  // getter/settter(プロパティ)
  get age(): number {
    return this._age;
  }
  set age(value: number) {
    this._age = value;
  }

  // コンストラクター
  constructor(name: string) {
    this.name = name;
  }

  // メンバーメソッド(パブリック)
  public say(): string {
    return this.getHelloString();
  }

  // メンバーメソッド(プライベート)
  private getHelloString(): string {
    return "Hello, " + name + "!";
  }
}

var hello = new Hello("慧");
hello.age = 17;
var words = hello.say(); // "Hello , " + name + "!"
var age = hello.age; // 17
リスト4 クラスの宣言と利用の例

 慧  初めて見るけど、何となく分かる気がするよ! class クラス名{}っていうのが大枠の構文で、コンストラクターは「constructor」って書くんだね。

 き  メンバー変数メンバー関数メンバーアクセッサもこんな感じで定義できるし、publicprivateといったアクセス修飾子も利用できる。

 その他、extendsキーワードを使った継承や、このあと紹介するimplementsキーワードによるインターフェースの実装といった、クラスベース・オブジェクト指向言語のクラスの多くが備えている機能があるので、そういった言語になじみがある人は大きな抵抗なく使えると思う。

 慧  プロトタイプベースって言われてもピンと来なかったから、これはうれしいな!

 き  そういう人も少なくないかもね(笑)。とはいえ、忘れてはいけないのは、コンパイルされて最終的に実行されるのはJavaScriptコードということ。先ほどのTypeScriptコードをコンパイルした結果のJavaScriptコードを見てみよう。

JavaScript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
var Hello = (function () {
  function Hello(name) {
    this.name = name;
  }
  Object.defineProperty(Hello.prototype, "age", {
    get: function () {
      return this._age;
    },
    set: function (value) {
      this._age = value;
    },
    enumerable: true,
    configurable: true
  });
  Hello.prototype.say = function () {
    return this.getHelloString();
  };
  Hello.prototype.getHelloString = function () {
    return "Hello, " + name + "!";
  };
  return Hello;
})();
リスト5 リスト4のコンパイル結果のJavaScriptコード
図1 Atomでのリスト4とリスト5の表示

 慧  JavaScriptでクラスっぽいことをやろうとすると、こんな感じになるんだね。私はちょっと苦手かも……。

 き  これはこれでJavaScriptの勉強になるから、一度、このコードの意味を追いかけてみるといいと思うよ。それはともかく、今回特に意識してほしいのは、18行目のgetHelloString関数のところ。何か気が付かない?

 慧  prototype…っていうのは置いておいていいんだよね……。何だろう?

 き  じゃあ、その一つ前のsay関数と見比べるとどうだろう?

 慧  うーんと……あ! 分かった。TypeScriptだとsay関数はpublicgetHelloStringprivateなのに、JavaScriptの方はどっちも指定が無いよ!

 き  正解! JavaScriptにはそもそもアクセス修飾子による制御は存在しないから、当然、コンパイルするとこうなってしまう。もちろん、TypeScript上はprivateのメンバーにアクセスするコードを書いてもコンパイラーがエラーにしてくれる。しかし、出来上がったJavaScriptのコードだけ利用するときは普通に利用できてしまうんだ。

 慧  なるほど。ちょっと気を付けておいた方がいいね!

インターフェース

 き  次はインターフェースを見てみよう。

 慧  インターフェースっていうと、これもJavaやC#なんかのオブジェクト指向言語でよくあるアレかな?

 き  そうだね、だいたい同じと思ってもいいかな。「メンバーの名前と型が定義された抽象的な型」だ。インターフェース自身はインスタンス化できないし、メンバー関数の中に処理を実装することもできない。

 慧  クラスで実装するんだよね!

 き  さすが、よく知っているね! クラスに対してインターフェースの実装を定義すると、インターフェースで定義されたメンバーの実装を強制できる。クラスを使う側からの視点で考えれば、インターフェースを実装しているクラスは、インターフェースで定義された通りのメンバーを持っていることが保証される。またTypeScriptでは、クラスで実装する以外に、変数宣言時などの型アノテーションとしても利用できる。ちょっと例を見てみよう。

TypeScript
interface IAnimal {
  name: string;
  makeSound(): string;
}

class Cat implements IAnimal {
  public name: string;
  constructor(name: string) {
    this.name = name;
  }
  public makeSound(): string {
    return "にゃー";
  };
}

var myCat : IAnimal;
myCat = new Cat("小鉄");

var sound = myCat.makeSound(); // 「ニャー」
リスト6 インターフェースの例

 慧  implementsを使って実装するんだね!

 き  この例のように、クラスCatにインターフェースIAnimalの実装を宣言すると、CatではIAnimalが持つメンバーを実装する必要がある。

 慧  当然、実装しなければコンパイルでエラーになるから、忘れることはなさそうだね!

 き  最後に、コンパイルされたJavaScriptコードを見てみよう。

JavaScript
var Cat = (function () {
  function Cat(name) {
    this.name = name;
  }
  Cat.prototype.makeSound = function () {
    return "にゃー";
  };
  ;
  return Cat;
})();
var myCat;
myCat = new Cat("小鉄");
var sound = myCat.makeSound();
リスト7 リスト6のコンパイル結果のJavaScriptコード
図2 Atomでのリスト6とリスト7の表示

 慧  あれ!? interfaceがまるっと無くなっているね。

 き  interfaceはコンパイル時にメンバーと型のチェックに使われるわけで、実行時にはもうその役目を終えている。具体的な実装を持たないから、そもそもJavaScriptコード上では表現のしようがない、ともいえるかもしれないね。

今、TypeScriptやって損しない?

 き  ちょっとここらあたりでいったん休憩にしようか

 慧  えー、私はまだまだいけるよ!

 き  まあ落ち着いて(笑)。取りあえずここまでで、TypeScriptの感想はどう?

 慧  思ったより簡単かも。JavaScriptと同じ感覚で書けるのに、JavaScriptにない便利な機能が使える、っていうのがいいね!

 き  そこが「JavaScriptのスーパーセット」ならでは、ってところだよね。

AltJSとTypeScript

 慧  でも少し不安もあるかな。今って、TypeScriptの他にも、JavaScriptに変換する言語がいっぱいあるでしょ?

 き  いわゆるAltJSといわれる言語だね。

 慧  今でもたくさんあるのに、将来もっといろいろな言語がいろいろ出てきて、TypeScriptが廃れちゃったら……損しない?

 き  そうだね。言語の将来性は気になるよね。これについては、僕はあんまり心配しなくていいと思っているよ。

 慧  どうして?

 き  あくまでも僕の個人的な考えだけど、こういう理由かな。

  • ECMAScript 6(後述)を意識して言語仕様を策定している
  • 出力されるJavaScriptの可読性が高い

ECMAScript 6を意識した言語仕様

 き  前回の最初の方で「TypeScriptはJavaScriptのスーパーセット」という話をしたけれど、これは今現在のJavaScriptだけではなくて、今現在、策定が進んでいるJavaScriptの次世代バージョン「ECMAScript 6」のスーパーセットを目指しているんだ。

 慧  ということは、将来のJavaScriptとも互換性があるってことかな?

 き  もちろん最終的にどうなるかは分からないよね。だけど、完全に独自の路線で言語仕様を策定する場合と比較すれば、将来のJavaScriptそのものとも乖離(かいり)も大きくならないことが期待できると思う。そのことは、JavaScriptにコンパイルされる言語としては小さくない意味を持つと思うんだ。

出力されるJavaScriptの可読性が高い

 慧  「出力されるJavaScriptの可読性」っていうのは、どういうこと?

 き  ここまででも、TypeScriptをコンパイルして出力されるJavaScriptのファイルをいくつか見てきたよね。これらは、人が読んでも十分に分かりやすく、JavaScriptコードとしてメンテナンス可能なものだと思う。

 慧  確かに、読んでいるとJavaScript自体の勉強にもなる気がしたよ!

 き  そしてこれは、もし万が一、TypeScriptが廃れてもソースコードが資産として生きることを意味すると僕は考えているんだ。

 慧  TypeScriptが無くなっても大丈夫ってこと?

 き  まあ、あんまりそうなってほしくはないけれどね(笑)。でも、これって、例えば何年も使われるようなシステムを開発する場合では特に無視できないと思っている。

 慧  とにかく、損はしないってことだね!

 き  そんなこんなを考えると、今、他のAltJSを使って開発しているならともかく、ナマでJavaScriptコードを書いているのであれば、TypeScriptを採用した方がメリットは大きい場合が多いと思う。最初に言ったことの繰り返しになるけど、「つまみ食い」……つまり、少しずつ学習しながら、使える機能・使いたい機能だけ使って開発するっていうのも十分アリなんじゃないかな。Better JavaScriptって感じかな。

 慧  なるほどね~。じゃ、なおさら早く続きをやりたいよ!

(続く。予告:次回は構造的部分型、ジェネリックス、アロー関数式といったTypeScriptの機能を紹介しつつ、今まで学んだことを使って、既存の著名なJavaScriptライブラリをTypeScriptから便利に使う例を一緒に勉強するよ!)

Build Insider × プロ生ちゃんの壁紙ダウンロード

 プロ生サイトで特別壁紙がダウンロードできます。

プロ生ちゃんと学ぶ! TypeScript入門(2)
1. TypeScriptってどんなもの? プロ生ちゃんと始めてみよう!

TypeScriptが気になる人は、本連載で楽しく優しく学ぼう。TypeScriptの特徴から、Atomエディター開発環境の構築まで紹介。

プロ生ちゃんと学ぶ! TypeScript入門(2)
2. 【現在、表示中】≫ TypeScriptの基本のキ。JavaScriptをベースに「TypeScriptをつまみ食い」しよう!

TypeScriptの基本中の基本である「型」「クラス」「インターフェース」をプロ生ちゃんと学ぼう。「今、TypeScriptやって損しない?」という疑問・不安についても回答する。

プロ生ちゃんと学ぶ! TypeScript入門(2)
3. TypeScriptの機能と文法、まずはこの3つを押さえよう! 構造的部分型、ジェネリクス、アロー関数式

TypeScriptには多くの機能や文法があり、最新の1.5~1.6でさらに追加された。開発の実践を始める前に、数ある機能の中から最低限、「構造的部分型」「ジェネリクス」「アロー関数式」の3つを押さえておこう。

サイトからのお知らせ

Twitterでつぶやこう!