TypeScript

[React][TypeScript] Hello World的なもの(1)は、動きもなくてつまらないので、他でも作ってるボタンを押したら「こんにちは!」って表示するやつを作ってみた。

003

コンポーネントにする必要なさそうなんだけど、「ボタンをおして!」を表示しているコンポーネントを作る。(Label.tsx)

import * as React from 'react';

export interface LabelProps {
    text:string;
}

// ラベルのコンポーネント
export class Label extends React.Component<LabelProps, {}>  {
    render() {
        return <span>{this.props.text}</span>;
    }
}

React.Componentを継承してLabelコンポーネントを作る。React.Componentのテンプレートで指定する1番目の型がpopsの型で2番目の型がstateの型になる。

ボタンとラベルコンポーネントがあるルートになるAppコンポーネントを作る。(App.tsx)

import * as React from 'react';
import { Label } from "./Label";

interface AppState {
    message:string;
}

export class App extends React.Component<{}, AppState>  {
    constructor(props:any) {
        super(props);
        this.state = {
            message:"ボタンを押して!"
        };

        this.onClick = this.onClick.bind(this);
    }

    // ボタンを押した時の処理
    onClick(e:any) {
        this.setState({message:"こんにちは!"});
    }
    render() {
        return <div>
            <p><Label text={this.state.message} /></p>
            <p><button type="button" onClick={this.onClick}>Button</button></p>
            </div>;
    }
}

ボタンを押した時の処理でthis.setStateをして表示するメッセージを更新している。
これを表示するhtmlファイルを作る。(index.html)

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
</head>
<body>
    <div id="root"></div>
    <script src="dist/app.js"></script>
</body>
</html>

htmlのrootにAppを割り当てるところを用いする。(index.tsx)

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { App } from "./App";

ReactDOM.render(
    <App />,
    document.getElementById('root')
);

ソース以外のビルド環境は[React][TypeScript] Hello World的なもの(1)で作ったのを使う。




最初、webpackを使わずに試してみようと思ったが面倒くさくなってきたので、ここを参考にビルド環境を用意した。
こっちにもざっくりと準備することを書いておく。

npm init

でpackage.jsonを用意して、scriptsのところに

  "scripts": {
    "build": "webpack --colors --config ./webpack.config.dev.js",
    "build:prod": "webpack --config ./webpack.config.prod.js"
  },

を追加。

webpackやらなんやらをインストールする。

npm i -D webpack typescript awesome-typescript-loader source-map-loader
npm i -S react react-dom @types/react @types/react-dom
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.1.3 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"ia32"})

って出るが、問題ないんだろうか?

TypeScriptの初期化。

tsc --init

tsconfig.jsonに追加変更する。

"module": "es2015",
"lib": ["dom", "es2017"],
"jsx": "react",
"outDir": "./dist/",
"sourceMap": true,

webpack.config.dev.jsを用意する。

module.exports = {
    // メインとなるJavaScriptファイル(エントリーポイント)
    entry: './src/index.tsx',
    // ファイルの出力設定
    output: {
        // 出力ファイル名
        filename: './dist/app.js'
    },
    module: {
        rules: [
            {
                // 拡張子 .ts もしくは .tsx の場合
                test: /\.tsx?$/,
                // TypeScript をコンパイルする
                use: 'awesome-typescript-loader'
            },
            // ソースマップファイルの処理
            {
                enforce: 'pre',
                test: /\.js$/,
                loader: 'source-map-loader'
            }
        ]
    },
    // import 文で .ts や .tsx ファイルを解決するため
    resolve: {
        extensions: [
            '.ts', '.tsx', '.js', '.json'
        ],
    },
    // ソースマップを有効にする
    devtool: 'source-map',
};

ReactのサイトにあるHello Worldみたいなもののindex.htmlとsrc/index.tsxを用意する。

index.html

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    <div id="root"></div>
    <script src="dist/app.js"></script>
</body>
</html>

src/index.tsx

import * as React from 'react';
import * as ReactDOM from 'react-dom';

ReactDOM.render(
    <h1>Hello world!</h1>,
    document.getElementById('root')
);
npm run build

でビルド、index.htmlをブラウザで開けば、Hello world!って表示される。

あと、JavaScriptのコードを圧縮するには、webpack.config.dev.jsのあたまに

const webpack = require('webpack');

と、module.exportsのところに、

    plugins: [
        // JSファイルのminifyを実行する
        new webpack.optimize.UglifyJsPlugin({
            // minify時でもソースマップを利用する
            sourceMap: true
        })
    ]

を追加する。




Typescript 2.6.1でlodashのchainを使ってるところでエラーになって困っていたんだが、とりあえず、回避方法がわかったので書いておく。

Typescriptのオプションでstrictをtrueにしていると、strictFunctionTypesオプションもtrueになってエラーになっているので、strictFunctionTypesをfalseでとりあえずエラーを回避できる。

strictFunctionTypesってなんぞやは、Typescript 2.6.1の変更点をググってみろ!w

(追記)
うーん、これでエラーにならなくなるけど、Visual Studio Codeでコード補完がおかしいような気がする。



↑このページのトップヘ