web-dev-qa-db-ja.com

TypeScriptでObject.prototypeを拡張する

現在、TypeScript APIに取り組んでいます。これには、Objectプロトタイプ(Object.prototype)にバインドするいくつかの追加機能が必要です。

次のコードを検討してください。

class Foo {

}

interface Object {
    GetFoo(): Foo;
    GetFooAsString(): string;
}

//This is problematic...
Object.prototype.GetFoo = function() {
    return new Foo();
    // Note, this line is just for testing...I don't want my function to just return a blank instance of Foo!
}

//This is ok.
Object.prototype.GetFooAsString = function () {
    return this.GetFoo().toString();
}

Playground でこれを直接試してみてください。

ご覧のとおり、Foo(実際に使用するオブジェクト名ではありません)というクラスがあります。また、Objectインターフェイスを拡張して、2つの新しい関数を追加しました。最後に、prototypeに対して関数を実装しました(これらは純粋なJavaScriptで機能します。文句を言うのはTypeScriptだけです)。

//これは問題があります...」という注釈を付けたところ、TypeScriptはこれを赤い波線で強調表示し、次のエラーを表示します:

Cannot convert '() => Foo' to '{ (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; }': Call signatures of types '() => Foo' and '{ (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; }' are incompatible
() => Foo

これは単なるTypeScriptのバグ(まだ開発段階にあることを知っているので、多くのバグを解決する必要があり、これらの一部をCodePlexで既に示しています)、または何かが足りません。

この問題が発生するのはなぜですか?

TypeScriptのバグでない場合、どうすれば修正できますか?

27
series0ne

以下に示すように、このバグはTS 0.9.0アルファで修正されています。 no error in Ts 0.9.0 alpha

遊び場はまだ0.8.3を実行しています。

これは基本的に、いくつかの主要なインターフェース(Object、Number、String)などのメソッドがパフォーマンスの最適化としてキャッシュされるために発生します。

これを実行する場合。初めてロードするときには、そのエラーは表示されません。 試してみてください

そのコードを編集するとすぐに、パーサーはコードを再度処理します。古いインターフェイス定義をキャッシュしたため、重複した関数定義が検出され、効果的に爆発します。そのファイルにさらに編集を加えると、エラーステートメントが複雑になります。

11
basarat

私はかつて持っていた:

// See if an array contains an object
Array.prototype.contains = function (obj) {
    var i = this.length;
    while (i--) {
        if (this[i] === obj) {
            return true;
        }
    }
    return false;
}

typeScriptでコードをコンパイルするために、次の行を追加しました。

interface Array {
    contains(obj: Object): boolean;
}

ありがとう basarat

18
Tono Nam

同じ方法で配列を拡張し、パーティーがfor i in ...を使用してループしているときに大きな問題に直面しました。これで、すべてのサードパーティコードを制御することはできず、これらのバグは非常に迷惑になる可能性があるため、より良い手順を提案します。

interface Array<T> {
   crandom(): T;
}

/** Retrieve a random element from the list */
 Object.defineProperty(Array.prototype, 'crandom', { value: function() {

    let index = Math.floor(Math.random() * this.length);

    return this[index];
}
});

これで、Object.definePropertyを使用することで、新しいプロパティが列挙されなくなり、安全になります。上記のコードは、配列からランダムな要素をほとんど与えます。配列からランダムな要素をポップする別のものも作成しました:

Object.defineProperty(Array.prototype, 'popRandom', { value: function() {

    let index = Math.floor(Math.random() * this.length);

    let result = this[index];
    this.splice(index, 1);

    return result;
}
});

Object.definePropertyを使用すると、この作成をより詳細に制御でき、制限を追加することもできます。

2
Arijoon