簡體   English   中英

通過 TypeScript 中的裝飾器向類添加屬性

[英]Adding properties to a class via decorators in 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失敗:

類型“Greeter”上不存在屬性“newProperty”。ts(2339)

錯誤並且它沒有在 VS Code 的提示中列出。 可以通過括號表示法訪問它,但 TS 警告說

元素隱式具有“任何”類型,因為類型“Greeter”沒有索引簽名。ts(7017)

我錯過了什么嗎? 如何以類型安全的方式通過裝飾器添加新屬性? 我想像普通的類成員一樣擁有普通的編譯器支持。

設計的裝飾器不能改變類的類型。 這仍在討論中,並且在裝飾器提案最終確定之前, 團隊似乎不會改變行為。 你可以使用 mixins 來完成這個任務(閱讀ts 中的 mixins

使用 mixins 的代碼看起來像:

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

const Greeter = classDecorator(class {
    property = "property";
    hello: string;
    constructor(m: string) {
        this.hello = m;
    }
});
type Greeter = InstanceType<typeof Greeter> // have the instance type just as if we were to declare a class

console.log(new Greeter("world").newProperty);
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

我能找到的最佳解決方案是:

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

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

注意:這不是最優的,因為它使Greeter.name返回一個空字符串! 該線程中的其他答案也是如此,所以我仍在尋找解決方案。

不是直接的解決方案,而是避免裝飾器限制的解決方法:在某些情況下,可以將裝飾器替換為可以正確繼承類型的普通類。

class ClassDecorator {
        newProperty = "new property";
        hello = "override";
}

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM