Edited at

なぜReact+TypeScriptでコンポーネント作成が早くなるのか

ReactアプリをTypeScriptで半年以上書いてきましたが、思ってた以上にメリットがあったので共有。

私も始めるまでは生JavaScriptでいいじゃないかと思っていました。


記述コストがほとんど変わらない

まずは気になる導入コスト。

普通にReactのコンポーネントを作ると、こんな感じになると思います。

import React from 'react';

class UserName extends React.Component {
render() {
return (
<div>
{this.props.name}さん。こんにちは。
</div>
);
}
}
UserName.propTypes = {
name: React.PropTypes.string,
};
export default UserName;

これをTypeScriptで書くとこうなります。

import * as React from 'react';

interface Props {
name: string,
}
interface State {}
class UserName extends React.Component<Props, State> {
render() {
return (
<div>
{this.props.name}さん。こんにちは。
</div>
);
}
};
export default UserName;

propTypes の書き方と書く位置が変わるだけ。stateに値を入れる場合はinterface State {}にPropsと同じような感じで指定してあげてください。

で、TypeScriptを書くと、どんないいことが起きるかというと


スニペットが効くようになる

たとえばvscodeで作成しているときに、this.props.まで打つとinterfacePropsで指定したリストが出てきます。わりと大きめのコンポーネントになってしまったときでも、補完でpropsの候補が出てくるのでかなり便利です。

上のコードでスニペットを試して見ると、this.props.まで打ったときに下のような感じに候補を出してくれます。

image


必須のPropsを書き漏らさなくなる

そして、コンポーネントを呼び出すときにもTypeScriptは仕事をしてくれます。

例えば、他のコンポーネントで上のコンポーネントを呼び出してみましょう。

import * as React from "react";

import UserName from './UserName';

interface Props {
name: string,
}
interface State {}
class UserNameParent extends React.Component<Props, State> {
render() {
return (
<div>
<UserName />
</div>
);
}
};
export default UserNameParent;

すると、このようなエラーが出ます。

image

UserNameのコンポーネントにはnameがPropsとして必須だよ、と教えてくれます。

ここで Ctrl + Space を押すとこの通り。コンポーネントのPropsに置けるものを表示してくれます。便利。

image


TypeScript 込みの開発環境も1コマンドで

便利なのはわかったが、TypeScript 込みの開発環境作るのが面倒なんだよ。という方もいると思います。

昔は環境構築が面倒でしたが、なんと今は1コマンド。

npx create-react-app my-app --typescript

my-app にアプリを名前を好きに入れてください。

より詳しくはこちら https://create-react-app.dev/docs/adding-typescript/


逆に不便になること

組み合わせることでReactのコンポーネントを作るのが非常に楽になるTypeScriptですが、もちろんデメリットもあります。


stateを使うときにconstructorが必須になる

コンポーネント内にこの記述が必須になります。

  constructor(props: any) {

super(props);
this.state = {
name: '',
};
}

これがないと、this.state.nameとしたときに、stateがundefinedなためnameを拾いに行けなくて落ちます。

面倒といえば面倒ですが、意図しないところでよくわからない挙動をされるよりはマシかなって思っています。


@ types

TypeScriptを使っているので型定義をする必要があります。npmモジュールも例外ではありません。なので、npmモジュールに対しても型定義をする必要があります。こちらも面倒ですね。

ただ安心してください。ほとんどのnpmモジュールに対して、TypeScript界隈の人が一生懸命型定義をしてくれています。大体の場合、使いたいパッケージhogehogeに対して、@types/hogehoge で検索すると出てきます。ありがたく使わせていただきましょう。

Qiitaで話題になってるようなモジュールであれば、ほぼあると思います。むしろ、@typesがないものを探すほうが大変なくらい。


サンプルがJavaScriptに比べて少なめ

もちろんサンプル数はJavaScriptに比べると少ないです。

しかし、有名なnpmモジュールにはTypeScriptの例が載っていることもありますし、いざとなればGithubで language=typescript で検索すると大体解決します。


TypeScript + Reactは思った以上に便利

TypeScriptに触れてしばらく経ちましたが、以前(といっても半年程度ですが)と比べて、npm界隈がTypeScriptを受け入れつつあるなというのを感じました。

ReadMeにTypeScriptのサンプルが載っている例が増えましたし、TypeScriptに対応したよ、というアップデートがあったりして、導入のコストはどんどんと下がってきています。

JavaScriptとの書き方の差異もかなり少ないので、もし気になっているならば是非試してみてください。