prop-typesか、それに代わる何かが必要な件
これまでReactコンポーネントを書く時、コンポーネントの使われ方を縛るためにprop-typesを用いて動的なチェックをしていました。TypeScriptでは代わって静的な型チェックを利用してprop-typesを使わずとも利用方法を縛るということになってます。しかし、けど漏れる。
import * as React from 'react'; import * as Redux from 'redux'; import * as ReactRedux from 'react-redux'; import * as Enzyme from 'enzyme'; test('HOC prop-types', () => { type Props = { greeting: string }; // greetingは?にしてない必須プロパティ const Target: React.StatelessComponent<Props> = (props) => { return <div className="target">{props.greeting}</div>; }; const Connected = ReactRedux.connect( state => state, dispatch => ({}), )(Target); // モックReducerをjest.fn()で作る const reducer = jest.fn().mockReturnValue({ /* greeting: 'hello' */ }); const store = Redux.createStore(reducer, {}); // HOCのため、Enzymeのmountでフルレンダリング const rendered = Enzyme.mount( <ReactRedux.Provider store={store}> <Connected /> </ReactRedux.Provider>); expect(rendered.find('.target').text()).toBe('hello'); // 上のコメント外さないと不合格 });
上記のJestテストはコンパイルできるけど合格しません。コメントを取り払ってモックReducerがgreetingプロパティを返すようにするとテストが通ります。React.Component
prop-typesも開発ビルド時にコンソールに警告を流してくれるだけですが、それでも静かにすまされるより良い。
また、TypeScriptで書いたモジュールコンポーネントを非TypeScript環境から使う場合には当然ゆるゆる。さてどうしたものでしょうか。prop-typesを二重に書くかと思ったけど、prop-typesの型定義が用意されていないみたい。まったく必要ないと思われているのかな?もしくは賢い、それに代わる何かがあるのか?Javaだとaptでやるような、TypeScriptコンパイラに差し込むプラグインが作れれば型情報から自動でプロテクトコードを挿入したりできるんでしょうけどね。
と、こんなのググったら出てきた。。。結構まどろっこしいな。でもio-tsね。。。
やっぱりあるんですか
Using the Compiler API · Microsoft/TypeScript Wiki · GitHub
あるよ、やっぱりASTとれるか。TypeScriptコンパイラがTypeScriptで書かれているってことだからなあ。
prop-typesを無理やり使えるかな?
この関数を作ったクラスのコンストラクタとかで呼べばいいのじゃないだろうかと思って、以下のように書いたら怒られた。直接呼ぶんじゃなく、PropTypes. checkPropTypes()を呼べという。。。
import * as PropTypes from 'prop-types'; PropTypes.object.isRequired(props, 'yourName', 'TargetComponent'); // -> 警告される。動かない。
https://github.com/facebook/prop-types/blob/master/README.md#proptypescheckproptypes
じゃあやってみようかと思っても、@types/prop-typesの型定義ファイルに、checkPropTypesが無かった。
import * as PropTypes from 'prop-types'; // あるはずのcheckPropTypesの型を定義 declare module 'prop-types' { function checkPropTypes<T>( typeSpecs: PropTypes.ValidationMap<T>, values: T, location: string, componentName: string, getStack?: () => string, ): void; } // TypeScript用のプロパティ定義 type Props = { yourName: string }; // PropTypes用のプロパティ定義 const YourTypes = { yourName: PropTypes.string.isRequired }; // テスト対象のプロパティ const props = { yourName: 'masataka_k' }; PropTypes.checkPropTypes<Props>(YourTypes, props, 'props', 'TargetComponent');
これで完璧!。PropTypes用のプロパティ定義をするのであれば、もっと簡単にECMAScriotで書く時と同様に、static propTypes = YourTypes; とだけで通常運転ですが、動的にチェックするプロパティ定義を組み立てることもできるのでこのテクニックは有用に思います。