TypeScriptによるStateless Functional Componentの定義

環境構築は create-react-appMicrosoft/TypeScript-React-Starterでサクッと行う

$ npx create-react-app my-app --scripts-version=react-scripts-ts
$ cd my-app
$ npm run start

以前、TypeScriptでReact app作ろうとしてセットアップに手間取ったときとは隔世の感がある。

type React.SFCを使う

@types/reactReact.SFC という型が用意されているので、これを使う

DefinitelyTyped/index.d.ts at master · DefinitelyTyped/DefinitelyTyped

    type SFC<P = {}> = StatelessComponent<P>;
    interface StatelessComponent<P = {}> {
        (props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null;
        propTypes?: ValidationMap<P>;
        contextTypes?: ValidationMap<any>;
        defaultProps?: Partial<P>;
        displayName?: string;
    }

type SFC<P = {}> とあるので、全てのpropsはoptionalにする必要がある。
そのため、requiredで定義すると以下のコンパイルエラーが発生する。

 error TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & AppProps & { children?: ReactNode; }'.
  Type '{}' is not assignable to type 'AppProps'.
    Property 'name' is missing in type '{}'.

コンポーネントの書き換え

App.tsxをStateless Functional Componentに書き換えるとこのようになる

import * as React from 'react';
import './App.css';

const logo = require('./logo.svg');

interface AppProps {
  name?: string;
}

const App: React.SFC<AppProps> = ({ name }) => {
  return (
    <div className="App">
      <div className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <h2>Welcome to {name}</h2>
      </div>
      <p className="App-intro">
        To get started, edit <code>src/App.tsx</code> and save to reload.
      </p>
    </div>
  );
};

App.defaultProps = {
  name: 'React.SFC',
};

export default App;

defaultPropsの定義をコンポーネント定義と分けたくない場合は、

const App: React.SFC<AppProps> = ({ name = 'React.SFC' }) => {
  return (
    <div className="App">
...

とも書ける