TypeScriptでReactを書きたかったので雑にメモする。
TypeScriptでJSXのコンパイル
Reactはまあ出来るとして、JSXがちゃんとコンパイル出来るのか疑問だったがTypeScript1.6から出来るらしい。2015.8.15現在のバージョンは1.5系なのでnextバージョンをインストールする必要あり。グローバルのtscは別プロジェクトで現行系を使いたいのでlocal installにした。
$ npm install typescript@next --save
JSXをコンパイルするには拡張子を.tsx
にする必要があるらしい。あとはコンパイル時に--jsx react
オプションが必要。
もろもろの事情によりタスクランナーはGruntを使っているため、自動コンパイルをしたかったのだが、grunt-typescriptだとどう設定しても.tsx
の拡張子は対応してませんと怒られた(設定方法が悪かったのかもしれない)。
追記;grunt-typescript
自体にtypescriptが入っていて、それのバージョンが調べた時点で1.5 beta
だった。1.5は正式版が出てるので、gruntはgrunt-ts
を使ったほうがいいのかもしれない。
一方grunt-tsなら次の設定でコンパイルが出来たのでこれを使うことにした。
dev: {
src: [
'assets/scripts/ts/**/*.ts', 'assets/scripts/ts/**/*.tsx'
],
options: {
noImplicitAny: false,
module: 'umd',
removeComments: true,
additionalFlags: '--jsx react',
fast: 'never'
}
}
あとは型定義ファイルのインストールも忘れずに
$ dtsm init
$ dtsm install react --save
Reactのビルドのためにbrowserifyを入れたりもするんだけど、その辺りはTypeで書こうが何で書こうが同じなので割愛。
実装
Reactコンポーネントをどうやって書くの?というところで若干詰まった。よく考えるとTypeScriptはES6をしっかりと追っかけているのでES6の例をだいたいそのまま持ってきたら動く。
React0.13から(?)、creatClass()をしなくてもES6 classでReact.component
を継承するとコンポーネントが作れるようになった。この点はTypeScriptも同じ(ジェネリクスだけ付けてあげればOK)。
ポイントはconstructor()
をしっかりと実装すること、super()を呼び出すことの2点。
/// <reference path="../../../typings/bundle.d.ts" />
import * as React from 'react';
class Hello extends React.Component<any, any> {
constructor(props) {
super(props);
this.state = {
count: 0
}
}
onClick() {
this.setState({ count: this.state.count + 1});
}
render() {
return (
<div>
<div>count, { this.state.count }</div>
<button onClick={ this.onClick.bind(this) }>UP!</button>
</div>
);
}
}
React.render(<Hello />, document.getElementById('app'));
あとはHTMLにタグを埋めたら表示される。
<div id="app"></div>
あと詰まったポイントはJSX内でthis.onClick.bind(this)
としている所。これをついthis.oncClick()
と書いてしまっていた。クラス内メソッドで定義されているonClick()なのでHelloにバインドされて呼び出されるかと思っていたら、そりゃDOMから直接(?)メソッドコールされるときはthis
変わるよね、という話。