こちらの記事の続編です。
http://qiita.com/uryyyyyyy/items/30733e9cd140e60c52bd
問題提起
今時、型のない言語とか使いたくないですよね!(JSerにケンカ売る挨拶)
今回はtodoListのサンプルを通じて、immutableJSの良さを再確認しましょう。
環境
- NodeJS 5.x~
- React 15.1
- TypeScript 1.8
構成
こちらをご参照ください。
https://github.com/uryyyyyyy/react-redux-sample/tree/immutable
Immutable.jsとは
JSでListやMapなどのコレクションを扱えるもの。
TypeScriptで使うと、ネイティブのArrayやObjectと比べて使えるメソッドが増えるのでオススメです。
(逆にJSで使うのであれば、ネイティブの型と混同しがちなのでlodashとかの方が良いのではないでしょうか?)
npm install immutable --save
typings install dt~immutable --global --save
ネイティブ型の場合
let list:number[] = [1, 2]
//そんなものはない。
list.isEmpty()
list.push(3)
list // [1,2,3] 破壊的メソッドコワイ
Immutable.jsのList型の場合
import {List} from "immutable";
let list:List<number> = List.of<number>(1, 2)
//ある!
list.isEmpty()
let newList = list.push(3)
list // [1,2] Immutable!
Immutable.jsでTodoList
基本コードを見てもらったほうが早いように思いますが、要点だけ。
const initialState:TodoState = {todos: List.of<Todo>(), marks: marks};
export function todoReduce(state: TodoState = initialState, action: MyAction): TodoState {
function changeStatus(state: TodoState, action: MyAction):TodoState {
const newTodos = state.todos.map(v => {
if (v.id === action.id) return new Todo(v.id, v.text, !v.isComplete);
return v
});
return objectAssign({}, state, {todos: newTodos});
}
function addTodo(state: TodoState, action: MyAction):TodoState {
let newNumber = 1;
if(!state.todos.isEmpty()) newNumber = state.todos.map(v => v.id).max() + 1;
const newTodo = new Todo(newNumber, action.text, false);
return objectAssign({}, state, {todos: state.todos.push(newTodo)});
}
function deleteTodo(state:TodoState, action:MyAction):TodoState {
return objectAssign({}, state, {todos: state.todos.filter(item => item.id !== action.id)});
}
}
export interface Props {
/* ... */
marks: Map<boolean, string>
}
render () {
return (
<li>
<span>{this.props.marks.get(this.props.item.isComplete)}: {this.props.item.text} </span>
/* ... */
);
}
どうですか。Immutable.Listのおかげで綺麗に書けてる気がしませんか?
(うーん。。この例だと言うほど便利じゃなさそうかも?まぁ、SetやStackなど色々な便利コレクションが同梱されているので、それ系に慣れている方だとかなり便利かと思います。)
注意点としては、jsonサーバーとの通信で来るjsonは勝手にImmutable.jsのオブジェクトにならないので、都度変換する必要があります。
const json: TodoInterface[] = [
{id: 1, text: "todo 1", isComplete: true},
{id: 2, text: "todo 2", isComplete: false}
];
const todos: List<TodoInterface> = List.of(...json);
逆にimmutable.jsオブジェクトからjsonへの変換は期待通りになります。