TypeScript `this` 入參


考察下面的示例代碼:

class MyClass {
  constructor(protected foo: string) {}

@MyDecorator
bar() {
console.log("bar");
}
}

function MyDecorator(
_target: any,
_key: string,
descriptor: PropertyDescriptor
) {
const original = descriptor.value;
descriptor.value = function(...args: any[]) {
// 🚨Property 'foo' does not exist on type 'PropertyDescriptor'.ts(2339)
console.log(this.foo);
return original.apply(this, args);
};
return descriptor;
}

const myClass = new MyClass("erm");
myClass.bar();

上面代碼定義了一個類 MyClass,包含一個 protected 類型的 foo 屬性。

同時定義了一個 MyDecorator 裝飾器,在被裝飾方法調用前訪問上面的 protected foo 屬性並且打印出來。

可以看到上面示例中,已經將 TypeScript 報錯標識了出來,可以看到此時 this 所指的對象其實不對,指向了 PropertyDescriptor,所以在裝飾器中試圖訪問 protected foo 時提示沒有 foo 屬性。

首先我們需要修正一下 this 的類型,因為該裝飾器修飾的是類的方法,所以 descriptor.valuethis 應該是被修飾方法所在的類才對。

function MyDecorator(
  _target: any,
  _key: string,
  descriptor: PropertyDescriptor
) {
  const original = descriptor.value;
  descriptor.value = function(...args: any[]) {
    // 🚨Property 'foo' does not exist on type 'PropertyDescriptor'.ts(2339)
    console.log((this as MyClass).foo);
    return original.apply(this, args);
  };
  return descriptor;
}

當我們試圖通過強制類型轉換修正 this 的類型時,發現新的錯誤出現了。因為 foo 被聲明成了 protected 類型,它提示只能在 MyClass 中或其繼承類中訪問該屬性。但我們明確知道,運行時 descriptor.value 確實是在這個類當中的。同時 Hover 到強制類型轉換后的 this 上發現其類型還是 PropertyDescriptor,說明強制類型轉換其實沒生效。

強制類型轉換失敗

強制類型轉換失敗

this 入參

對於這種需要修正函數中 this 所指的場景,TypeScript 提供了一種機制,可以在函數入參列表中第一個位置處,手動寫入 this 標識其類型。但這個 this 入參只作為一個形式上的參數,供 TypeScript 做靜態檢查時使用,編譯后是不會存在於真實代碼中的。

function f(this: void) {
    // make sure `this` is unusable in this standalone function
}

像上面這樣,f 被指定了 this 類型為 void,即 f 這個函數的函數體內,不允許使用 this。這有什么用呢,請看以下示例:

interface UIElement {
  addClickListener(onclick: (this: void, e: Event) => void): void;
}
class Handler {
  constructor(public info: string) {}
  onClickBad(this: Handler, e: Event) {
    this.info = e.type;
  }
}
let h = new Handler('foo');
// 🚨error
uiElement.addClickListener(h.onClickBad); 

上面 uiElement.addClickListener 聲明了只接收一個不依賴於 this 上下文的函數做為回調,但我們傳入的 h.onClickBad 聲明為它執行時依賴於 Handler 這個上下文。因此顯式地修正函數的執行上下文可讓 TypeScript 檢查出相關的錯誤。

回到文章開頭的示例,我們就知道如何修正它了。

只需要將設置 descriptor.value 地方,為其添加上 this 入參即可保證正確的上下文了。

function MyDecorator(
  _target: any,
  _key: string,
  descriptor: PropertyDescriptor
) {
  const original = descriptor.value;
-  descriptor.value = function(..args: any[]) {
+  descriptor.value = function(this: MyClass, ...args: any[]) {
    console.log((this as MyClass).foo);
    return original.apply(this, args);
  };
  return descriptor;
}

相關資源


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM