Posted at
CureAppDay 3

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

More than 1 year has passed since last update.


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

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

// 使いたいライブラリの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で困る

[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だと、


DefinitelyTyped/DefinitelyTyped/blob/types-2.0/keymirror/index.d.ts

declare function KeyMirror(obj: {}): { [key: string]: string };

export = KeyMirror;

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


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://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さんです