web-dev-qa-db-ja.com

TypeScriptのデコレータを介してクラスにプロパティを追加する

TypeScriptのデコレータリファレンスページには、コンストラクタをクラスデコレータでオーバーライドする方法を示すコードが抜粋されています。

function classDecorator<T extends {new(...args:any[]):{}}>(constructor:T) {
    return class extends constructor {
        newProperty = "new property";
        hello = "override";
    }
}

@classDecorator
class Greeter {
    property = "property";
    hello: string;
    constructor(m: string) {
        this.hello = m;
    }
}

console.log(new Greeter("world"));

およびログ:

class_1 {
  property: 'property',
  hello: 'override',
  newProperty: 'new property' }

ここまでは順調ですね。しかし、ドット表記でnewPropertyにアクセスしようとすると、次のように失敗します。

プロパティ「newProperty」はタイプ「Greeter」に存在しません。ts(2339)

エラーが発生し、VSCodeのヒントにリストされていません。ブラケット表記でアクセスできますが、TSは次のように警告しています。

タイプ「Greeter」にはインデックス署名がないため、要素には暗黙的に「any」タイプがあります。ts(7017)

私は何かが足りないのですか?タイプセーフな方法でデコレータを介して新しいプロパティを追加する方法を実装するにはどうすればよいですか?通常のクラスメンバーと同じように、通常のコンパイラサポートが必要です。

5
Forseti
function classDecorator<T extends { new(...args: any[]): {} }>(constructor: T) {
    return class extends constructor {
        newProperty = "new property";
        hello = "override";
    }
}
interface classInterface {
    newProperty: string;
    hello: string;
}

//trick
interface Greeter extends classInterface { };

@classDecorator
class Greeter {
    property = "property";
    hello: string;
    constructor(m: string) {
        this.hello = m;
    }
}
const b = new Greeter();
console.log(b.newProperty);

インターフェイストリックを使用して問題を解決できるようです。トリックのリファレンス: https://stackoverflow.com/a/52373394/4831179

1
blackmiaool