TypeScript
SIMD.js

SIMD.jsの型定義ファイルを作ってみた

More than 1 year has passed since last update.

SIMD.js (ES.next stage3)の記事を書きつつ、実際に試してみるために欲しかったのでSIMD.jsのTypeScript用型定義ファイルを作ってみた

完成品(ver.0.9.1対応)

やったこと

  • DefinitelyTyped で探す
    • → ない。 Issueが立っていたが特に動きなし。
  • ドキュメントを探す
  • polyfillのコードを読む
    • 挙動の参考にはなったが、型情報という意味では普通のJSなのであまり。。。
  • polyfillをdtsmakeに読ませてみる
    • 普通のライブラリと違うせいか、一部のメソッドのみしか出力されず
    • 内部で使っているTern.jsがちゃんと解析できてない
  • 手書きしてみる
    • ほとんど同じだけど引数の型が違うメソッドが、ある型にはあるけどこっちには無い、といったことがあり、早々にあきらめる
  • 生成用のコードを書く
    • polyfill&Node.jsを--harmony_simdで一部有効にした上で解析し、引数の型やJSDocコメントなどを一つ一つ手作業で出力するようにした
    • 仕様のver. UPにもすぐ対応できるように
    • ついでに簡易テストコードも生成

書き方でなやんだこと

  • SIMDオブジェクトは名前空間なのでnamespaceで定義して悩まなかった
  • それぞれの型のコンストラクタはnewできないのでinterfaceかfunctionかどちらで定義すべきか
  • SIMD型の固有メソッドはすべてstaticなので、namespace内で定義するかinterface内で定義するか
    • interfaceだとしたとき、interface名は%SIMD%Constructor%SIMD%Static?
  • 共通メソッドをまとめてinterfaceに定義して、各SIMD型のinterfaceで継承させる?させない?
  • 新しいプリミティブなデータ型をどう表現する?

最終的に

declare namespace SIMD{
    /**
     * 128-bits divided into 4 lanes storing single precision floating point values.
     */
    interface Float32x4{
        constructor: Float32x4Constructor;
        valueOf(): Float32x4;
        toLocaleString(): string;
        toString(): string;
        /**
         * The initial value of the @@toStringTag property is the String value "SIMD.Float32x4".
         */
        [Symbol.toStringTag]: string;
        [Symbol.toPrimitive](hint: "string"): string;
        [Symbol.toPrimitive](hint: "number"): number;
        [Symbol.toPrimitive](hint: "default"): Float32x4;
        [Symbol.toPrimitive](hint: string): any;
    }
    interface Float32x4Constructor{
        /**
         * SIMD.Float32x4 constructor
         * @param s0 A 32bit float specifying the value of the lane. 
         * @param s1 A 32bit float specifying the value of the lane. 
         * @param s2 A 32bit float specifying the value of the lane. 
         * @param s3 A 32bit float specifying the value of the lane. 
         * @return SIMD.Float32x4 object 
         */
        (s0?: number, s1?: number, s2?: number, s3?: number): Float32x4;

        prototype: Float32x4;
//...(中略)
    }
    var Float32x4: Float32x4Constructor;
//...(略)
}

色々試行錯誤したが最終的には上記の方式に落ち着いている。lib.d.tsなど公式の組み込みオブジェクトで使われている方法に近い。

宿題1:プリミティブデータ型の表現

SIMD型は新しいデータ型なので、Numberに対するnumber, Stringに対するstringのように本来はTypeScriptの本体側がプリミティブデータ型として認識できなければいけない。厳密にいえば、例えば SIMD.Float32x4 の コンストラクタで返す型は ラッパーの Float32x4ではなくて "float32x4"であるべきなのかもしれない。だが、普通の型定義ファイルの中でそういうものが定義できるのかわからない&やってよいのか分からないのでラッパーinterfaceだけの定義にとどめた。

宿題2:DefinitelyTypedへプルリク

  • JSDocが不十分。基本MDNからの引用なのでライセンス上の問題なくするなら書き換えないといけない?
  • 標準APIだからlib.d.tsとかにマージすべき?
  • まだstage3。stage4になるまで待つべき?