LoginSignup
37
21

More than 5 years have passed since last update.

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

Posted at

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.

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


明日は@shinoutさんです

37
21
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
37
21