@typesの型定義ファイルがES6モジュール非対応だったときにすること

## Typescript 2.0以降の型定義ファイルの管理方法

`v1.0`系の頃は

```ts
/// <reference path="../../types/angularjs/angular-mocks.d.ts"/>
/// <reference path="../../types/jasmine/jasmine.d.ts"/>
/// <reference path="../../types/mousetrap/mousetrap.d.ts"/>
/// <reference path="../../types/mousetrap/keyevent.d.ts"/>
/// <reference path="../ts/references.ts"/>
```
と、毎回手書きしたりコピペしたりgrunt plugin使ったりと頑張ってました

それと比べると、かなりシンプルになってます
v2.0以降は、型定義ファイルはnpmで追加削除できます

```bash
// インストール
npm i @types/mocha
npm i @types/redux
npm i @types/react
```

- [@types](https://www.npmjs.com/~types) 以下に型定義ファイルがpublishされてる
    - 現時点で2,400以上のの型定義ファイルが登録
    - 型定義ファイルは、[DefinitelyTypedのtype-2.0ブランチ](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/types-2.0)でメンテされてる
- `@types`のように`@`が先頭についたパッケージは、scoped packageとよばれる
    - [scope | npm Documentation](https://docs.npmjs.com/misc/scope)

型定義ファイルも使いやすくなった

```ts
// 使いたいライブラリのd.tsファイルはビルド時に自動的に参照される
import * as React from 'react';
import { render } from 'react-dom';
```

```ts
//型のimportもこんな風にかける
import { Action } from 'redux';
```

## とはいえ、`@types` の型定義ファイルだけで解決しない場合も

- たまにそういうパッケージに当たることがある
- 例えば[keymirror](https://www.npmjs.com/package/keymirror)
    - flux/reduxアプリでaction typeを定義するときのヘルパーとして使われてるやつ


```ts
import * as keyMirror from 'keymirror';
```

と書くとコンパイルエラーになる

```bash
ERROR in ./src/constants/actionTypes.ts
(6,28): error TS2497: Module '"/Users/sakymark/proj/node_modules/@types/keymirror/index"'
resolves to a non-module entity and cannot be imported using this construct.
```

ES6モジュールのシンタックスに非対応でエラー出てるので、コンパイル通すためには

```ts
import keyMirror = require('keymirror');
```

という風にかかないとダメ

## `import xxx = require('xxx')` と書くと困ること

単に見た目（ES6モジュールとCommonJSが混ざったような外見）とは別に困ること

### TSLintで困る

- [no-require-imports](https://palantir.github.io/tslint/rules/no-require-imports/)
    - このルールが使えなくなる

```bash
[6, 21]: require() style import is forbidden
```

- 大半の`@types/..../indx.d.ts`は、ES6モジュールのシンタックスに対応してる
- `import xxx = require('xxx')` とないといけない型定義ファイルは一部

そういう状況だと

- keymirrorとかのためだけに、ルール "no-require-imports" をオフ
    - ES6モジュールで書いたり、`import xxx = require('xxx')`で書いたりバラバラな感じにする
- 全部 `import xxx = require('xxx')` に統一する

どっちも解決方法としてはビミョーな感じがする

## ES6モジュールで解決するためのやり方（ad hocな解決）

ES6モジュールのシンタックスに対応した型定義ファイルを書けばOK

例えば[@types/keymirror](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/types-2.0/keymirror/index.d.ts#L6-L7)だと、

```ts:DefinitelyTyped/DefinitelyTyped/blob/types-2.0/keymirror/index.d.ts
declare function KeyMirror(obj: {}): { [key: string]: string };
export = KeyMirror;
```

という風にしか型定義をexportしていないのが原因なので

```ts:types/index.d.ts
declare module "keymirror" {
  function KeyMirror(obj: {}): { [key: string]: string };
  namespace KeyMirror { }
  export = KeyMirror;
}
```

と書いてプロジェクトに保存すれば、ES6モジュール形式で書いてもコンパイルが通る

## DefinitelyTyped

こっちの型定義ファイルが対応してくれればよい。が、作法的なものが。。。

### 曰く、`import * as foo from 'foo'` 目的の `namespace foo {}` 追加はNG
DefinitelyTyped的にはそういうルール
>* `namespace foo {}`:
    Do not add a namespace just so that the `import * as foo` syntax will work.
    If it is commonJs module with a single export, you should use the `import foo = require("foo")` syntax.
    See more explanation [here](https://stackoverflow.com/questions/39415661/why-cant-i-import-a-class-or-function-with-import-as-x-from-y).

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/types-2.0/README.md#common-mistakes


なので、`import * as foo = require('foo')`する他なく、上の`namespace KeyMirror { }`が入った型定義ファイルをPRにして送ることもNG
使いたいモジュール側が、`exports.default = ...`という形でexportされるようになれば、使えるはず

---
明日は@shinoutさんです