8279


TypeScriptでDraggabillyを使いたいと考えています。以下のようにd.tsファイルを記述し、  
ファイルの冒頭で読み込んでいます。

typings/draggabilly/draggabilly.d.ts

[code]

    declare module 'draggabilly' {
      export class Draggabilly {
        x: number;
        y: number;
        constructor(container: any, options: any);
        disable(): void;
        enable(): void;
        destroy(): void;
      }
    }
    
[/code]

src/renderers/ScrollBarRenderer.ts

[code]

    /// <reference path="../../typings/draggabilly/draggabilly.d.ts" />
    import draggabilly = require('draggabilly');
    
[/code]

しかし、この定義だと`import draggabilly = require('draggabilly')`としたときに  
実際にはClass定義が読み込まれますが、コンパイラ上はモジュールが読み込まれたことに  
なってしまい、クラスをそのまま使えません。

どのようにd.tsファイルを定義したらDraggabillyをTypeScriptで使えるのでしょうか。


CC BY-SA 3.0
2015-03-23T13:58:09.297
8274
2015-12-12T18:22:31.940
2298
question
javascript node.js typescript
TypeScriptでDraggabillyを使いたい


以下の様に定義すれば使えるかと思います。

**型定義ファイル:**

[code]

    declare module draggabilly {
      export class Draggabilly {
        x: number;
        y: number;
        constructor(container: any, options: any);
        disable(): void;
        enable(): void;
        destroy(): void;
      }
    }
    import Draggabilly = draggabilly.Draggabilly;
    
    declare module "draggabilly" {
        import Draggabilly = draggabilly.Draggabilly;
        export = Draggabilly;
    }
    
[/code]

**ts:**

[code]

    /// <reference path="./typings/draggabilly/draggabilly.d.ts" />
    import Draggabilly = require("draggabilly");
    
    var draggie = new Draggabilly(".draggable", {
        // options...
    });
    
    var htmlElement = document.getElementById("#draggable");
    var draggie = new Draggabilly(htmlElement, {
        // options...
    });
    
    var element = document.querySelector(".draggable");
    var draggie = new Draggabilly(element, {
        // options...
    });
    
    var draggableElems = document.querySelectorAll(".draggable");
    var draggies: Draggabilly[] = [];
    for (var i = 0, len = draggableElems.length; i < len; i++) {
        var draggableElem = draggableElems[i];
        var draggie = new Draggabilly(draggableElem, {
            // options...
        });
        draggies.push(draggie);
    }
    
[/code]

**補足：**

`\--module`オプションなしでJavaScriptにコンパイルする場合、`import Draggabilly =
require("draggabilly");`は不要です。

また、1つのクラスだけの型定義であれば、以下の様に書くこともできます。

[code]

    declare class FooClass {
    }
    
    declare module "fooClass" {
        export = FooClass;
    }
    
[/code]

[code]

    declare module "fooClass" {
        class FooClass {
        }
    
        export = FooClass;
    }
    
[/code]

ただし、1つ目の例ではトップレベルにclassやinterfaceが並び名前空間が汚染されることと、名前が重複したinterfaceがあった場合に定義が統合(マージ)されてしまう問題があります。

2つ目は、`FooClass`を使用するのに必ず`require("fooClass")`しなければいけない問題があります。こうしてしまうとHTMLページで`draggabilly.pkgd.min.js`を読み込んで使用するJavaScriptが書けません。(グローバルで`Draggabilly`が使用できないと困る)

### 余談

参考として、[Draggabillyのドキュメント](http://draggabilly.desandro.com/)をもとに型定義ファイルを作ってみました。

  * `TouchEvent`等を扱うのに[touch-events.d.ts](https://github.com/borisyankov/DefinitelyTyped/blob/master/touch-events/touch-events.d.ts)が必要です
  * `on()`の型定義の書き方については[TypeScriptの型定義ファイル](https://github.com/Microsoft/TypeScript/blob/f61d07db69487d55ddec411ad0ff98f53f4b5102/src/lib/dom.generated.d.ts#L281)が参考になるかと思います
  * `Options`インターフェースを作りましたが、`any`型で良いかと思います

**ディレクトリ:**

[code]

    typings
     ├─ draggabilly
     |   └─ draggabilly.d.ts
     └─ touch-events
         └─ touch-events.d.ts
    
[/code]

**型定義ファイル:**

[code]

    /// <reference path="../touch-events/touch-events.d.ts"/>
    declare module draggabilly {
        export class Draggabilly {
            x: number;
            y: number;
    
            constructor(node: Node, options?: Options);
            constructor(selector: string, options?: Options);
    
            disable(): void;
            enable(): void;
            destroy(): void;
    
            on(type: "dragStart",   listener: (ev: MouseEvent | TouchEvent, pointer: MouseEvent | Touch) => any): any;
            on(type: "dragMove",    listener: (ev: MouseEvent | TouchEvent, pointer: MouseEvent | Touch, moveVector: any) => any): any;
            on(type: "dragEnd",     listener: (ev: MouseEvent | TouchEvent, pointer: MouseEvent | Touch) => any): any;
            on(type: "pointerDown", listener: (ev: MouseEvent | TouchEvent, pointer: MouseEvent | Touch) => any): any;
            on(type: "pointerMove", listener: (ev: MouseEvent | TouchEvent, pointer: MouseEvent | Touch, moveVector: any) => any): any;
            on(type: "pointerUp",   listener: (ev: MouseEvent | TouchEvent, pointer: MouseEvent | Touch) => any): any;
            on(type: "staticClick", listener: (ev: MouseEvent | TouchEvent, pointer: MouseEvent | Touch) => any): any;
            on(type: string,        listener: (...params: any[]) => any): any;
            off(type: string,       listener: (...params: any[]) => any): any;
            once(type: string,      listener: (...params: any[]) => any): any;
        }
    
        interface Options {
            axis?: string;
            containment?: Node | string | boolean;
            grid?: number[];
            handle?: string;
        }
    }
    import Draggabilly = draggabilly.Draggabilly;
    
    declare module "draggabilly" {
        import Draggabilly = draggabilly.Draggabilly;
        export = Draggabilly;
    }
    
[/code]


CC BY-SA 3.0
2015-03-23T16:45:00.613
8279
2015-12-12T18:22:31.940
2015-12-12T18:22:31.940
3068
3068
8274
answer