ReduxのTutorialをTypeScriptでやってみました. (n番煎じ)
とりあえずの自分なりのベストプラクティスを書き記します.
$ create-react-app <App名> --scripts-version=react-scripts-ts # TypeScriptで作成.
$ yarn add redux react-redux #reduxを追加
$ yarn add -D @types/react-redux tslint-config-airbnb # reduxのtypeと、air-bnbのtslintを追加.自らを律すため、tslint-config-airbnbを導入.
globalを
"globals": {
"window": true,
"location": true,
"document": true
},とか書いとくと良い.
詳しいrulesは tslint.json を確認.
Actionは Flux Standard Action を参考にして、値は payload 内に格納するように実装.
interfaceは Redux のActionをextendsしておく.
interface AddTodoAction extends Action {
type: ActionTypes.ADD_TODO;
payload: {
id: number;
text: string;
};
}また、ActionTypeはenumとして定義することで、よりsafeな実装に.
export enum ActionTypes {
ADD_TODO = 'ADD_TODO',
SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER',
TOGGLE_TODO = 'TOGGLE_TODO',
}Reducerのaction引数の型を指定するために、TodoActionsという共有型としてtypeをexportしておくと良い.
export type TodoActions = AddTodoAction | SetVisibilityFilterAction | ToggleTodoAction;Stateは states/ 内でinterface定義. 各stateはReduxの思想に乗っ取り、readonlyに指定する.
ObjectなStateも定義しておくことで、各所でtypeを利用できて便利.
export interface TodoState {
readonly id: number;
readonly text: string;
readonly completed: boolean;
}また、Storeで保持されるRootのStateをinterfaceで定義することで、ドキュメント的にStateの内部を記述しておける.
export interface State {
readonly visibilityFilter: VisibilityFilters;
readonly todos: TodoState[];
}素直に実装すれば良い.
Presentational componentなので、基本的にSFCになるよう実装.
引数の props はTutorial内では ({ active, children, onClick }) のように記述されていたが、こちらを参考に、関数内でpropsを展開.
やってることは変わらないので、好みで決めていいと思う. 個人的に、引数に書くと変数定義部が冗長になりすぎてしまうので、関数内のほうが好み.
各componentのpropsはOwnPropsとしてinterfaceを定義.
export interface OwnProps {
active: boolean;
onClick: () => any;
}
const Link: React.SFC<OwnProps> = (props) => {
const { children, active, onClick } = props;
return (
<button
onClick={onClick}
disabled={active}
style={{
marginLeft: '4px',
}}
>
{children}
</button>
);
};
export default Link;Provider直下のAppもSFCでいいと思う.
const App: React.SFC = () => (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
);
export default App;やり過ぎ感はあるが、 mapStateToProps の戻り値として、 StateToProp interface、 mapDispatchToProps として、 DispatchToProps interface を定義.
interface StateToProps {
todos: TodoState[];
}
interface DispatchToProps {
toggleTodo: (id: number) => any;
}Tutorialの AddTodo は connect()(AddTodo) されたことで、AddTodoのtypeが曖昧になってしまうので、 connect()(AddTodo) したものを、そのままexportすると良い.
2018.4.13