search
LoginSignup
49

More than 5 years have passed since last update.

posted at

updated at

TypeScript の JSX/React サポートを試す

1.5.0-beta には入っていません (2015/07/21 追記: 1.5.3 にも入っていません。 1.6 で入る模様) が、 TypeScript の master ブランチでは、 JSX/React がサポートされています。

React/Flux の TodoMVC のサンプルコードを、これを使って TypeScript 化してみました。

コードはこちらから見られます。

こちらのサイトの説明を参考にさせていただきました。

ポイント

  • JSX を書くときは拡張子を .tsx にする
  • component は React.Component<P, S> を extends したクラスを作成する
    • P は props の型、 S は state の型
    • React.createClass で作ると、クラス内での this の参照がうまく解決できないので避けたほうがよいと思われる
  • getInitialState() は、 React.createClass で作ったクラスでしか機能せず、上記の方法でクラスを作った場合は使えない
    • メソッドを定義するとコンソールに warning が出力され、実際 state が undefined になってしまう
    • constructor で初期化すれば OK (constructor の引数が props なので、 state の初期値が props に依存する場合でも対応可)
  • tsc のオプションの --jsx
    • preserve: jsx の記法のまま (<div/> -> <div/>)
    • react : react のメソッドを使った記法に変換される (<div/> -> React.createElement("div"))
    • サンプルコードでは、 JS 変換後に reactify とかするのが面倒だったので、 --jsx react しました

サンプル

一例として、 TodoTextInput.tsx のコードを貼っておきます。

/// <reference path="../../typings/tsd.d.ts" />
import * as React from 'react';

let ENTER_KEY_CODE = 13;

export interface Props {
    className?: string;
    id?: string;
    placeholder?: string;
    onSave: (value: string) => void;
    value?: string;
}

export default class TodoTextInput extends React.Component<Props, {value: string;}> {

    constructor(props: Props) {
        super(props);
        this.state = { 'value': props.value ? props.value : '' };
    }

    render(): JSX.Element  {
        return (
            <input
                className={this.props.className}
                id={this.props.id}
                placeholder={this.props.placeholder}
                onBlur={() => {
                    this.save();
                }}
                onChange={(event: React.FormEvent) => {
                    this.onChange(event);
                }}
                onKeyDown={(event: React.KeyboardEvent) => {
                    this.onKeyDown(event);
                }}
                value={this.state.value}
                autoFocus={true}
            />
        );
    }

    private save(): void {
        this.props.onSave(this.state.value);
        this.setState({ 'value': '' });
    }

    private onChange(event: React.FormEvent): void {
        this.setState({ 'value': event.target['value'] });
    }

    private onKeyDown(event: React.KeyboardEvent): void {
        if (event.keyCode === ENTER_KEY_CODE) {
            this.save();
        }
    }

}

ちなみに

単に TypeScript の JSX/React サポートを試すだけなら、 component だけ書いておけばよかったわけですが、なぜ Flux 一式書いてみたかというと、 ts-eventemitter という自作ライブラリを試してみたかったからです。

それについては別途記事を書く予定です。 -> 書きました TypeScript の機能で EventEmitter のイベントの payload を型安全に扱う

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
49