Published using Google Docs
TypeScript勉強会ハンズオン資料
Updated automatically every 5 minutes

あんざいゆき

2013年1月25日

TypeScript勉強会/ハンズオン資料 TypeScriptでDOM入門 by あんざいゆき is licensed

under a Creative Commons 表示 - 非営利 - 改変禁止 3.0 非移植 License.

docs.google.comにある作品に基づいている。

TypeScript勉強会/ハンズオン資料

 TypeScriptでDOM入門

この資料のURL : https://docs.google.com/document/d/1ptwDE9rlIVF-cx2_p4VfL4FRnfWihpGQH9F2AKTf6ys/pub

注意:この資料は羊さん向けです。


0. 準備

1. DOM について

index.html

index.html

index.html

index.html

script.js

2. TypeScript をコンパイルして JavaScript を生成する

script.ts

script.js

3. 型情報を付加する

script.ts

script.js

4. Module を使う

script.ts

script.js

5. TypeScript で jquery を使う

script.ts

script.ts

6. 応用編: タイピングゲームを作る



0. 準備

コードを書くエディタを用意する。

別にメモ帳でもいいと思いますが、私は Sublime Text 2 を使っています。

わかめは最近 WebStorm を使っているらしい。

1. DOM について

TypeScript 以前に DOM がよくわかってない羊さんのために、まず DOM についてちょっと書きます。

詳しくは http://y-anz-m.blogspot.jp/2012/12/jquery-dom.html で紹介した羽田野さんの本を読んでもらうのがいいと思います。

DOM は Document Object Model の略で、JavaScript から HTML 文書を操作するためのインタフェースの仕様です。

“「DOMとは、プログラムやスクリプトからダイナミックに、文書の内容・構造・スタイルにアクセスでき、そしてそれをアップデートできる、プラットフォームや言語に依存しないインタフェースである」 - W3C の仕様から引用 ”

要するに、JavaScript でなんらかの処理を行った結果をブラウザのページに表示するためには、DOM を操作して(DOM のインタフェースから)表示させる必要があるということです。

■ id 属性値から要素を取得する

<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

</head>

<body>

    <h1 id="title"></h1>

</body>

</html>

このときに

var elm = document.getElementById(“title”);

とすると、id=”title” となっている要素を取得することができます。

そこで、これを使って id=”title” の <h1> に “Hello World” と表示させてみます。

index.html


<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

</head>

<body>

    <h1 id="title"></h1>

    <script type="text/javascript">

        var elm = document.getElementById("title");

        var tNode = document.createTextNode("Hello World");

        elm.appendChild(tNode);

    </script>

</body>

</html>


id は一意に割り当てます。もし同じ id の要素が複数ある場合、ブラウザによって挙動がかわる(返ってくる要素が異なる)可能性があります。

他にも

 ・getElementsByTagName

 ・getElementsByName

などがありますが、以下では使わないので自分で勉強してください。

<h1>Hello World</h1>

という HTML の場合、Hello World の部分は TextNode というノードになります。そのため、createTextNode() で TextNode を作成し、<h1> である ElementNode に appendChild() で追加することが必要です。

ただし、単に中身を入れ替えたい場合なら

elm.innerHtml = hoge;

elm.innerText = hoge;

のほうが簡単です。

次に、ボタンにイベントリスナーをセットして、テキストボックスに入力された文字を先ほどの <h1> に表示するようにしてみます。

index.html


<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

</head>

<body>

    <h1 id="title"></h1>

    <input type="text" id="input_title" />

    <input type="button" id="enter_btn" value="set title" />

    <script type="text/javascript">

        var elm = document.getElementById("title");

        // ボタンのエレメントにクリックのイベントリスナーを追加

        var btnElm = document.getElementById("enter_btn");

        btnElm.addEventListener("click", setTitle, false);

        // テキストボックスのエレメントを取得

        var inputElm = document.getElementById("input_title");

        // ボタンがクリックされたときに呼ばれる

        function setTitle (evt) {

            // h1 の中身をテキストボックスの値に置き換える

            var title = inputElm.value;

            elm.innerText = title;

        }

    </script>

</body>

</html>


addEventListener(type, listener, useCapture) を使ってイベントリスナーを追加します。削除するには

removeEventListener(type, listener, useCapture) を使います。

type は “click” や “load” などイベントの種類を指定します。

listener はイベントが発生したときに呼ばれる関数を指定します。

useCapture はイベントの補足をバブリング・フェーズで行いたい場合に true を指定します。バブリング・フェーズについては羽田野さんの本を読んでください。

エレメントの属性を操作する場合は、エレメントのプロパティを直接操作します。

例えば、

<input type=”text” id=”input_title” value=”Hello World” />

というエレメントがあった場合、

inputElm = document.getElementById(“input_title”);

var text = inputElm.value;

で value 属性にセットされている値(= Hello World  )が取得できます。また、

inputElm.value = “Hello DOM”;

で、value 属性の値をセットすることができます。

今まで、<script> 部分を <body> の最後に書いていましたが、これは document.getElementById() などで参照するエレメントが生成された後にスクリプトを実行しないとエラーになるからです。

そこで、window に load イベントのリスナーをセットして、<script> 部分を <header> 部分に移してみます。

index.html


<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

    <script type="text/javascript">

    var titleElm;

    var inputElm;

    function init() {

        titleElm = document.getElementById("title");

        // ボタンのエレメントにクリックのイベントリスナーを追加

        var btnElm = document.getElementById("enter_btn");

        btnElm.addEventListener("click", setTitle, false);

        // テキストボックスのエレメントを取得

        inputElm = document.getElementById("input_title");

    }

    // ボタンがクリックされたときに呼ばれる

    function setTitle (evt) {

        // h1 の中身をテキストボックスの値に置き換える

        var title = inputElm.value;

        titleElm.innerText = title;

    }

    window.addEventListener("load", init, false);

    </script>

</head>

<body>

    <h1 id="title"></h1>

    <input type="text" id="input_title" />

    <input type="button" id="enter_btn" value="set title" />

</body>

</html>


ここまできたら、JavaScript を外部ファイルに外出ししましょう。

index.html


<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

    <script type="text/javascript" src="script.js"></script>

</head>

<body>

    <h1 id="title"></h1>

    <input type="text" id="input_title" />

    <input type="button" id="enter_btn" value="set title" />

</body>

</html>


script.js


var titleElm;

var inputElm;

function init() {

    titleElm = document.getElementById("title");

    // ボタンのエレメントにクリックのイベントリスナーを追加

    var btnElm = document.getElementById("enter_btn");

    btnElm.addEventListener("click", setTitle, false);

    // テキストボックスのエレメントを取得

    inputElm = document.getElementById("input_title");

}

// ボタンがクリックされたときに呼ばれる

function setTitle (evt) {

    // h1 の中身をテキストボックスの値に置き換える

    var title = inputElm.value;

    titleElm.innerText = title;

}

window.addEventListener("load", init, false);


2. TypeScript をコンパイルして JavaScript を生成する

上記の script.js を script.ts に置き換えてみましょう。

そのまま script.ts として保存して tsc コマンドを使って .js ファイルを生成してみます。

> tsc script.ts

なにも言われなければ script.js が生成されているはずです。

script.ts


var titleElm;

var inputElm;

function init() {

    titleElm = document.getElementById("title");

    // ボタンのエレメントにクリックのイベントリスナーを追加

    var btnElm = document.getElementById("enter_btn");

    btnElm.addEventListener("click", setTitle, false);

    // テキストボックスのエレメントを取得

    inputElm = document.getElementById("input_title");

}

// ボタンがクリックされたときに呼ばれる

function setTitle (evt) {

    // h1 の中身をテキストボックスの値に置き換える

    var title = inputElm.value;

    titleElm.innerText = title;

}

window.addEventListener("load", init, false);


script.js


var titleElm;

var inputElm;

function init() {

    titleElm = document.getElementById("title");

    var btnElm = document.getElementById("enter_btn");

    btnElm.addEventListener("click", setTitle, false);

    inputElm = document.getElementById("input_title");

}

function setTitle(evt) {

    var title = inputElm.value;

    titleElm.innerText = title;

}

window.addEventListener("load", init, false);


生成された .js ファイルは、コメントが削除され改行も最小限になっています。

0.8.2 からコメント付きでコンパイルできる -c オプションが追加されたらしい by vvakame

↑ jsdoc に対応するためらしい

このままでは JavaScript のままなので、TypeScript の利点を活かすように書き換えていきましょう。

1. 型情報を付加する

2. Module を使う

3. 型情報を付加する

TypeScript では : (コロン)の後に型情報を書きます。

var text : string = “hoge”;

var score : number = 10;

getElementById で取得したエレメントは HTMLElement という型のオブジェクトになります。ただし、value 属性は HTMLElement にはありません。これは HTMLInputElement というオブジェクトになります。

TypeScript では <> を使ってキャストするので、

var inputElm : HTMLInputElement = <HTMLInputElement> document.getElementById()

のように書く事ができます。

ちなみに、createTextNode() で作成したテキストノードは Text という型のオブジェクトになります。

script.ts


var titleElm : HTMLElement;

var inputElm : HTMLInputElement;

function init() {

    titleElm = document.getElementById("title");

    // ボタンのエレメントにクリックのイベントリスナーを追加

    var btnElm : HTMLElement = document.getElementById("enter_btn");

    btnElm.addEventListener("click", setTitle, false);

    // テキストボックスのエレメントを取得

    inputElm = <HTMLInputElement> document.getElementById("input_title");

}

// ボタンがクリックされたときに呼ばれる

function setTitle (evt : Event) {

    // h1 の中身をテキストボックスの値に置き換える

    var title : string = inputElm.value;

    titleElm.innerText = title;

}

window.addEventListener("load", init, false);


文字列の型の string の s は大文字ではなく小文字です。

この TypeScript をコンパイルして見ましょう。

生成された JavaScript では型情報がなくなっているのがわかります。

script.js


var titleElm;

var inputElm;

function init() {

    titleElm = document.getElementById("title");

    var btnElm = document.getElementById("enter_btn");

    btnElm.addEventListener("click", setTitle, false);

    inputElm = document.getElementById("input_title");

}

function setTitle(evt) {

    var title = inputElm.value;

    titleElm.innerText = title;

}

window.addEventListener("load", init, false);


4. Module を使う

TypeScript には Module という機能が用意されています。

これを使うと、名前空間を定義することができます。Java でいうところのパッケージみたいなもんです。

script.ts


module Sample1 {

    var titleElm: HTMLElement;

    var inputElm: HTMLInputElement;

    function init() {

        titleElm = document.getElementById("title");

        // ボタンのエレメントにクリックのイベントリスナーを追加

        var btnElm: HTMLElement = document.getElementById("enter_btn");

        btnElm.addEventListener("click", setTitle, false);

        // テキストボックスのエレメントを取得

        inputElm = < HTMLInputElement > document.getElementById("input_title");

    }

    // ボタンがクリックされたときに呼ばれる

    function setTitle(evt: Event) {

        // h1 の中身をテキストボックスの値に置き換える

        var title: string = inputElm.value;

        titleElm.innerText = title;

    }

    window.addEventListener("load", init, false);

}


これを JavaScript に変換すると次のようになります。

script.js


var Sample1;

(function (Sample1) {

    var titleElm;

    var inputElm;

    function init() {

        titleElm = document.getElementById("title");

        var btnElm = document.getElementById("enter_btn");

        btnElm.addEventListener("click", setTitle, false);

        inputElm = document.getElementById("input_title");

    }

    function setTitle(evt) {

        var title = inputElm.value;

        titleElm.innerText = title;

    }

    window.addEventListener("load", init, false);

})(Sample1 || (Sample1 = {}));


module 名として指定した Sample1 が var として用意され、処理が無名関数の中に入るようになります。

5. TypeScript で jquery を使う

TypeScript で jquery を使うには必要なファイルが2つあります。

1. jquery-x.x.x.min.js

2. jquery.d.ts

jquery-x.x.x.min.js は jquery の本体です。1.7.2 だと何かがうまくいかなかったことがあるので(何がうまくいかなかったかは忘れた)、1.8 以降がいいと思います。

http://jquery.com/download/

最新は 1.9 みたいですね(1.9 出てたのか... )。

jquery.d.ts は jquery の型情報が定義されたファイルです。

TypeScript のコードと一緒に公開されていますが、1.7.x 向けのままっぽい(1.8 以降で定義されたメソッドとかを使うときに困るかも?)

http://typescript.codeplex.com/SourceControl/changeset/view/258e00903a9e#typings/jquery.d.ts

TypeScript で外部の TypeScript ファイルのコードを参照するには、ファイルの最初に次のように宣言します。path= はファイルの場所の相対パスです(絶対パスや URL でもできるかは知らん)。

/// <reference path="hoge.ts" />

jquery を使う場合は、jquery の型定義ファイルを次のように宣言します。

/// <reference path="jquery.d.ts" />

jquery では、

getElementById(hoge)        →        $("#hoge");

のように書く事ができます。

$(...) で返ってくるオブジェクトは JQuery 型になります。

script.ts


/// <reference path="jquery.d.ts" />

module Sample1 {

    var titleElm: JQuery;

    var inputElm: JQuery;

    function init() {

        titleElm = $("#title");

        // ボタンのエレメントにクリックのイベントリスナーを追加

        var btnElm: JQuery = $("#enter_btn");

        btnElm.addEventListener("click", setTitle, false);

        // テキストボックスのエレメントを取得

        inputElm = $("#input_title");

    }

    // ボタンがクリックされたときに呼ばれる

    function setTitle(evt: Event) {

        // h1 の中身をテキストボックスの値に置き換える

        var title: string = inputElm.value;

        titleElm.innerText = title;

    }

    window.addEventListener("load", init, false);

}


JQuery 型には value というプロパティは存在していません。変わりに val() というメソッドが用意されています。

また、JQuery 型には innerText というプロパティも存在していません。変わりに text() や html() というメソッドが用意されています。

document.getElementById(hoge)        →        $("#hoge")

hoge = elem.value                        →        hoge = elem.val()

elem.value = hoge                        →        elem.val(hoge)

elem.innerText = hoge                →        elem.text(hoge)

elem.innerHtml = hoge                →        elem.html(hoge)


    function setTitle(evt: Event) {

        // h1 の中身をテキストボックスの値に置き換える

        var title: string = inputElm.val();

        titleElm.text(title);

    }


JQuery 型には addEventListener() というメソッドも用意されていません。変わりに各イベント毎のメソッドが用意されています。クリックしたときのイベント用のメソッドは click() です。

elem.addEventListener(“click”, hoge, false)                →        elem.click(hoge)

1.8 くらいから次の書き方のほうが推奨されているらしい by vvakame

elem.addEventListener(“click”, hoge, false)                →        elem.on(“click”, hoge)


        // ボタンのエレメントにクリックのイベントリスナーを追加

        var btnElm: JQuery = $("#enter_btn");

        btnElm.click(setTitle);


DOM の準備が出来たあとに実行するために window に load イベントのリスナーをセットしていましたが、jquery では

$(document).ready(function() {

    ...

}

$(function() {

    ...

}

のように記述することができます。

最終的にはこんな感じになります。

script.ts


/// <reference path="jquery.d.ts" />

module Sample1 {

    var titleElm: JQuery;

    var inputElm: JQuery;

    // ボタンがクリックされたときに呼ばれる

    function setTitle(e: Event) {

        // h1 の中身をテキストボックスの値に置き換える

        var title: string = inputElm.val();

        titleElm.text(title);

    }

    $(function() {

        titleElm = $("#title");

        // ボタンのエレメントにクリックのイベントリスナーを追加

        $("#enter_btn").click(setTitle);

        // テキストボックスのエレメントを取得

        inputElm = $("#input_title");

    });

}


HTML の方にも jquery を <script> で定義するのを忘れずに!

index.html


<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

    <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.3.min.js"></script>

    <script type="text/javascript" src="script.js"></script>

</head>

<body>

    <h1 id="title"></h1>

    <input type="text" id="input_title" />

    <input type="button" id="enter_btn" value="set title" />

</body>

</html>


6. 応用編: タイピングゲームを作る

余裕があったらやってみるべし。

・ランダムでアルファベット1文字を表示

→ <h1> の部分を応用すべし!

・テキストボックスに入力があった時点で入力文字列をチェック

→ keydown() か keyup() か on(“keyup”, listener) とか

・テキストボックスの入力文字が表示している文字と同じだったら、次の文字を表示

→ val() の部分を応用すべし

・入力にかかった時間が短いほど高得点

■ 1. 画面を用意する

・問題を表示するエリア

・答えを入力するテキストボックス

・得点を表示するエリア

<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

    <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.3.min.js"></script>

    <script type="text/javascript" src="script.js"></script>

</head>

<body>

    <h1 id="question"></h1>

    <input type="text" id="input_answer" />

    <h2 id="score"></h2>

</body>

</html>

■ 2. ランダムに問題を表示する

ヒント : Math.random()

/// <reference path="jquery.d.ts" />

module Sample1 {

    // 問題を表示するエリア

    var questionArea : JQuery;

    // 答えを入力するテキストボックス

    var answerInput : JQuery;

    // スコアを入力するエリア

    var scoreArea : JQuery;

    var questions = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];

    function showNextQuestion() {

        // ランダムに次の問題を選択

        var index : number = Math.floor(Math.random() * questions.length);

        questionArea.text(questions[index]);

    }

    $(function() {

        questionArea = $("#question");

        answerInput = $("#input_answer");

        scoreArea = $("#score");

        showNextQuestion();

    });

}

リロードしたら問題が変更されたらOK

■ 3. 文字が入力されたら、問題と答えを比較する

/// <reference path="jquery.d.ts" />

module Sample1 {

    // 問題を表示するエリア

    var questionArea : JQuery;

    // 答えを入力するテキストボックス

    var answerInput : JQuery;

    // スコアを入力するエリア

    var scoreArea : JQuery;

    var questions = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];

    var currentQuestion : string;

    // ランダムに次の問題を表示

    function showNextQuestion() {

        var index : number = Math.floor(Math.random() * questions.length);

        currentQuestion = questions[index];

        questionArea.text(currentQuestion);

    }

    // 入力された答えを問題と比較し、合っていれば次の問題を表示

    function checkAnswer {

        var answer : string = answerInput.val();

        if(answer === currentQuestion) {

            // 次の問題に行く時は、テキストボックスをクリア

            answerInput.val("");

            showNextQuestion();

        }

    }

    $(function() {

        questionArea = $("#question");

        answerInput = $("#input_answer");

        scoreArea = $("#score");

        answerInput.keyup(checkAnswer);

        showNextQuestion();

    });

}

問題と同じ文字をテキストボックスに入れたら、次の問題が表示されればOK

■ 4. 得点を計算する

例えば、

(10 - かかった秒数)> 0 ? (10 - かかった秒数) * 10 : 0

とか

ヒント: (new Date()).getTime() で 1970年1月1日0時0分0秒(UTC)からの秒数(ミリ秒単位)を取得

/// <reference path="jquery.d.ts" />

module Sample1 {

    // 問題を表示するエリア

    var questionArea : JQuery;

    // 答えを入力するテキストボックス

    var answerInput : JQuery;

    // スコアを入力するエリア

    var scoreArea : JQuery;

    var questions = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];

    var currentQuestion : string;

    var startTime : number;

    var currentScore : number = 0;

    // ランダムに次の問題を表示

    function showNextQuestion() {

        var index : number = Math.floor(Math.random() * questions.length);

        currentQuestion = questions[index];

        questionArea.text(currentQuestion);

        startTime = (new Date()).getTime();

    }

    // 入力された答えを問題と比較し、合っていれば次の問題を表示

    function checkAnswer() {

        var answer : string = answerInput.val();

        if(answer === currentQuestion) {

            // 次の問題に行く時は、テキストボックスをクリア

            answerInput.val("");

            updateScore();

            showNextQuestion();

        }

    }

    function updateScore() {

        var endTime : number = (new Date()).getTime();

        var score : number;

        if(!startTime) {

            score = 0;

        }

        else {

            score = endTime - startTime;

        }

        if(score < 0) {

            score = 0;

        }

        else {

            score = score * 10;

        }

        currentScore += score;

        scoreArea.text(currentScore.toString());

    }

    $(function() {

        questionArea = $("#question");

        answerInput = $("#input_answer");

        scoreArea = $("#score");

        answerInput.keyup(checkAnswer);

        showNextQuestion();

    });

}

こんな感じやでー

7. もう少し TypeScript っぽくする

class を使ってみる。

class のシンタックス from http://phyzkit.net/typescript/index.html#chapter3_section10

class className extends superClass implements interface1, ... {
   
   // クラス変数
   
varName : varType = expression ;
   
   // メンバ関数
   
funcName(arg1 : arg1Type, arg2 : arg2Type, ...) : returnType {
       ...
   }

   // コンストラクタ
   
constructor(arg1 : arg1Type, arg2 : arg2Type, ...) {
       ...
   }
   
   // get アクセサ
   
get getAccessorName() : returnType {
       ...
   }
   
   // set アクセサ
   
set setAccessorName(arg : argType) {
       ...
   }
   
   // 静的クラス変数
   
static varName : varType = expression ;
   
   // 静的メンバ関数
   
static funcName(arg1 : arg1Type, arg2 : arg2Type, ...) : returnType {
       ...
   }
}

注意点

・クラス変数には var を付けない

・クラスのメンバ関数には function を付けない

・クラス変数にアクセスするときは this をつける

・イベントリスナーのセットでは

            this.answerInput.on("keyup", (event: JQueryEventObject) => {

               this.checkAnswer(event);

            });

のように => を介さないと checkAnswer() のなかでの this がクラスのインスタンスにならない

script.ts


/// <reference path="jquery.d.ts" />

module Sample1 {

    class TypingGame {

        // 問題を表示するエリア

        private questionArea : JQuery;

        // 答えを入力するテキストボックス

        private answerInput : JQuery;

        // スコアを入力するエリア

        private scoreArea : JQuery;

        private questions = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];

        private currentQuestion : string;

        private startTime : number;

        private currentScore : number = 0;

        constructor(q : JQuery, a : JQuery, s : JQuery) {

            this.questionArea = q;

            this.answerInput = a;

            this.scoreArea = s;

        }

        public start() {

            //

            this.answerInput.on("keyup", (event: JQueryEventObject) => {

               this.checkAnswer(event);

            });

            this.showNextQuestion();

        }

        public stop() {

            this.answerInput.off("keyup", (event: JQueryEventObject) => {

               this.checkAnswer(event);

            });

        }

        // ランダムに次の問題を表示

        private showNextQuestion() {

            var index : number = Math.floor(Math.random() * this.questions.length);

            this.currentQuestion = this.questions[index];

            this.questionArea.text(this.currentQuestion);

            this.startTime = (new Date()).getTime();

        }

        // 入力された答えを問題と比較し、合っていれば次の問題を表示

        private checkAnswer(e : JQueryEventObject) {

            var answer : string = this.answerInput.val();

            if(answer === this.currentQuestion) {

                // 次の問題に行く時は、テキストボックスをクリア

                this.answerInput.val("");

                this.updateScore();

                this.showNextQuestion();

            }

        }

        private updateScore() {

            var endTime : number = (new Date()).getTime();

            var score : number;

            if(!this.startTime) {

                score = 0;

            }

            else {

                score = endTime - this.startTime;

            }

            if(score < 0) {

                score = 0;

            }

            else {

                score = score * 10;

            }

            this.currentScore += score;

            this.scoreArea.text(this.currentScore.toString());

        }

    }

    $(function() {

        var game : TypingGame = new TypingGame(

            $("#question"),

            $("#input_answer"),

            $("#score"));

        game.start();

    });

}


interface を使ってみる。

script.ts


/// <reference path="jquery.d.ts" />

module Sample1 {

    class TypingGameModel {

        private questions = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];

        private currentQuestion : string;

        private startTime : number;

        private currentScore : number = 0;

        private listener : TypingGameListener;

        public setListener(l : TypingGameListener) {

            this.listener = l;

        }

        public start() {

            this.listener.onStart();

            this.nextQuestion();

        }

        public stop() {

            this.listener.onStop();

        }

        // 次の問題をランダムに選択

        private nextQuestion() {

            var index : number = Math.floor(Math.random() * this.questions.length);

            this.currentQuestion = this.questions[index];

            this.startTime = (new Date()).getTime();

            this.listener.updateQuestion(this.currentQuestion);

        }

        // スコアを計算

        private calculateScore() {

            var endTime : number = (new Date()).getTime();

            var score : number;

            if(!this.startTime) {

                score = 0;

            }

            else {

                score = endTime - this.startTime;

            }

            if(score < 0) {

                score = 0;

            }

            else {

                score = score * 10;

            }

            this.currentScore += score;

            this.listener.updateScore(this.currentScore);

        }

        // 渡された答えが現在の問題と同じか比較、同じなら次の問題を表示

        public checkAnswer(answer : string) {

            if(answer === this.currentQuestion) {

                // 次の問題に行く時は、テキストボックスをクリア

                this.calculateScore();

                this.nextQuestion();

            }

        }

    }

    interface TypingGameListener {

        updateQuestion(question : string);

        updateScore(score : number);

        onStart();

        onStop();

    }

    class TypingGameRender implements TypingGameListener {

        // 問題を表示するエリア

        private questionArea : JQuery;

        // 答えを入力するテキストボックス

        private answerInput : JQuery;

        // スコアを入力するエリア

        private scoreArea : JQuery;

        private typingGameModel : TypingGameModel;

        constructor(m :TypingGameModel) {

            this.questionArea = $("#question");

            this.answerInput = $("#input_answer");

            this.scoreArea = $("#score");

            this.typingGameModel = m;

        }

        private onStart() {

            this.answerInput.on("keyup", (event: JQueryEventObject) => {

               this.onInputAnswer(event);

            });

        }

        private onStop() {

            this.answerInput.off("keyup", (event: JQueryEventObject) => {

               this.onInputAnswer(event);

            });

        }

        // 新しい問題を画面上に表示

        private updateQuestion(question : string) {

            this.questionArea.text(question);

            this.answerInput.val("");

        }

        // 新しいスコアを画面上に表示

        private updateScore(score : number) {

            this.scoreArea.text(score.toString());

        }

        // 入力された値を取得し、問題と比較

        private onInputAnswer(e : JQueryEventObject) {

            var answer : string = this.answerInput.val();

            this.typingGameModel.checkAnswer(answer);

        }

    }

    $(function() {

        var model : TypingGameModel = new TypingGameModel();

        var render : TypingGameRender = new TypingGameRender(model);

        model.setListener(render);

        model.start();

    });

}


8. おまけ

このサイトの説明がすごくいいです!

http://phyzkit.net/typescript/index.html

  TypeScript 勉強会 / TypeScript で DOM 入門    /