Typescript 2.0以降の型定義ファイルの管理方法
v1.0
系の頃は
/// <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で追加削除できます
// インストール
npm i @types/mocha
npm i @types/redux
npm i @types/react
-
@types 以下に型定義ファイルがpublishされてる
- 現時点で2,400以上のの型定義ファイルが登録
- 型定義ファイルは、DefinitelyTypedのtype-2.0ブランチでメンテされてる
-
@types
のように@
が先頭についたパッケージは、scoped packageとよばれる
型定義ファイルも使いやすくなった
// 使いたいライブラリのd.tsファイルはビルド時に自動的に参照される
import * as React from 'react';
import { render } from 'react-dom';
//型のimportもこんな風にかける
import { Action } from 'redux';
とはいえ、@types
の型定義ファイルだけで解決しない場合も
- たまにそういうパッケージに当たることがある
- 例えばkeymirror
- flux/reduxアプリでaction typeを定義するときのヘルパーとして使われてるやつ
import * as keyMirror from 'keymirror';
と書くとコンパイルエラーになる
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モジュールのシンタックスに非対応でエラー出てるので、コンパイル通すためには
import keyMirror = require('keymirror');
という風にかかないとダメ
import xxx = require('xxx')
と書くと困ること
単に見た目(ES6モジュールとCommonJSが混ざったような外見)とは別に困ること
TSLintで困る
-
no-require-imports
- このルールが使えなくなる
[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')
で書いたりバラバラな感じにする
- ES6モジュールで書いたり、
- 全部
import xxx = require('xxx')
に統一する
どっちも解決方法としてはビミョーな感じがする
ES6モジュールで解決するためのやり方(ad hocな解決)
ES6モジュールのシンタックスに対応した型定義ファイルを書けばOK
例えば@types/keymirrorだと、
declare function KeyMirror(obj: {}): { [key: string]: string };
export = KeyMirror;
という風にしか型定義をexportしていないのが原因なので
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 theimport * as foo
syntax will work.
If it is commonJs module with a single export, you should use theimport foo = require("foo")
syntax.
See more explanation here.
なので、import * as foo = require('foo')
する他なく、上のnamespace KeyMirror { }
が入った型定義ファイルをPRにして送ることもNG
使いたいモジュール側が、exports.default = ...
という形でexportされるようになれば、使えるはず
明日は@shinoutさんです