react-dnd の tutorial を typescript mobx で写経した

# 目的

typescript と react-dnd と mobx を使う場合に、デコレータの組み合わせでどうなるか、を確認したかった。

# 経緯

mobx使ってる個人的なプロジェクトで、drag and drop したいかも。と思って、
`react drag and drop` でググってトップに出てきた react-dnd さんを確認してた

<img src="https://qiita-image-store.s3.amazonaws.com/0/28895/071e3a76-723e-01af-4db3-33bc24e5b7c1.png" width="700px">


[ドキュメント](http://react-dnd.github.io/react-dnd/docs-overview.html)読んでて、デコレータ使ってた

<img src="https://qiita-image-store.s3.amazonaws.com/0/28895/a9850bd0-380c-03a0-eee1-9263f8a24e01.png" width="700px">

mobx との相性問題とか出ないのかな。と気になったので
<img src="https://s3.amazonaws.com/f.cl.ly/items/1F2g2F0D470X0d0k2A1U/Screen%20Recording%202015-05-15%20at%2002.22%20pm.gif" width="300px">

の [チュートリアル](http://react-dnd.github.io/react-dnd/docs-tutorial.html) を写経ついでにmobx化


# 成果物

* ソースコード
    * https://codesandbox.io/s/k36n9m0wvv
* デモ
    * https://k36n9m0wvv.codesandbox.io/


# Tips

## storeを参照したいreact-dndのデコレータに@injectつける

```tsx:Chessboard.tsx
@inject("gameStore")
@DropTarget(
  ItemTypes.KNIGHT,
  BoardSquare.squareTarget,
  BoardSquare.dropCollector
)
class BoardSquare extends React.Component<
```

DropTargetに渡した squareTarget さんは、
BoardSquare を使う側で渡したpropsを使ってゴニョゴニョする。


```tsx:Chessboard.tsx
@DropTarget(
  ItemTypes.KNIGHT,
  BoardSquare.squareTarget,
  BoardSquare.dropCollector
)
@inject("gameStore")
class BoardSquare extends React.Component<
```

この順だと、 squareTarget から gameStore を参照できない。

ちなみに squareTarget.drop だと第３引数に component が渡されてくる。
squareTarget.propsで頑張る方向もあるのかな。と思ってたのだけど、
canDrop を使い始めたところで第３引数が無くて死んだ。
DropTargetから見ると子となる、BoardSquareの状態を読むような形は作りとして微妙な感じがするので、
inject -> DropTarget で propsを引き継ぐのがきっと良いのだと納得することにした。



## collector の型がpropsに渡されてくるので使いやすいように頑張る

react-dnd と mobx の組み合わせというより、react-dnd と typescript 的なTips

```tsx:Chessboard.tsx
type OptionalPropertyNames<T> = { [K in keyof T]?: T[K] };
type OptionalReturnType<
  T extends (...args: any[]) => any
> = OptionalPropertyNames<ReturnType<T>>;
```

ReturnTypeだけだと以下のようなOptionalじゃない型が取れるので、

```ts
interface {
  connectDragSource: Function;
  connectDragPreview: Function;
  isDragging: Function;
}
```

使うところで上記のprops指定しないとエラーになってしまう。

それを抑制しつつ、中ではpropsとして使えるように、`OptionalReturnType` というものを拵えた。
（そもそも ２．８から入った ReturnType を知らなくて、これ便利と、大興奮。）
（別件で `React.Component<P, S>` の `P` を使ってゴニョゴニョしてどこかで幸せになれないかな。と思ってる。）


## 細かい変更

### source/collector を componentのstaticメソッドにしてみた

```tsx:Chessboard.tsx
@DragSource(ItemTypes.KNIGHT, Knight.dragSource(), Knight.dragCollector)
class Knight extends React.Component<
```

### 操作なり状態について処理するときはstoreに任せるようにした

```tsx:Chessboard.tsx
  static squareTarget = {
    canDrop(props, src) {
      return props.gameStore.canMoveKnight(props.x, props.y);
    },
    drop(props, src, component) {
      props.gameStore.moveKnight(props.x, props.y);
    }
  };
```


# 参考サイト

* react-dnd
    * react-dnd https://github.com/react-dnd/react-dnd
    * ドキュメント http://react-dnd.github.io/react-dnd/docs-overview.html
    * チュートリアル http://react-dnd.github.io/react-dnd/docs-tutorial.html
* Qiita 
    * `react-コンポーネント > drag-and-drop` https://qiita.com/sugasaki/items/dcf893e0189042468f88
        * 他にもこんなものがあるのかーと眺めている最中
        * react-dnd は touch に対応してないのか。なるほど。etc

# Appendix

* codesandbox https://codesandbox.io/
    * 初めて使ったけど、結構使えるなー。と思った
    * 微妙に使いづらい所はあった
        * auto-reload でプレビューがエラーになる
        * 間違ってforkしちゃった
        * project 読み込み直したらエラーいっぱいになった