類型 - 使用字串存取 TypeScript 的選用物件屬性
我正在一個現有的 JavaScript 代碼庫中工作。有一個類別提供預先定義的函數(例如「copy」、「paste」)作為工具。該類別可以通過「extension」函數實例化,允許使用者註冊其他工具函數以便日後使用。
這段程式碼沒有使用類型,因此我正在嘗試為函式簽名添加類型。但我在取得工具函式的函式(get(name))上遇到很多麻煩。程式碼的簡化版本(包含我嘗試添加的類型)如下:
class Operation {
private extensions: {[key: string]: () => void}
constructor(extensions: {[key: string]: () => void}) {
this.extensions = extensions;
}
get(name: string): () => void {
if (this[name]) {
return this[name].bind(this)
}
if (this.extensions[name]) {
return this.extensions[name].bind(this)
}
// default to copy
return this.copy.bind(this);
}
copy() {
console.log('copied');
}
paste() {
console.log('pasted');
}
}
const operation = new Operation({'cut': () => { console.log('cut'); }});
operation.get('cut')();
這失敗是因為 this[name]:"元素隱式具有 'any' 類型,因為類型 'Operation' 沒有索引簽名 ts(7053)"。
由於這個函數是用來接受任意字串(因為有覆寫),我認為我無法避免將函數輸入類型寫成 get(name: string)。我無法從 TypeScript 文件中弄清楚如何使用條件類型,例如 get(name: string | keyof Operation),而且我也不確定那是不是正確的解決方案。
在嚴格類型下,對於 get(name) 函數,給定 name 不保證是 Operation 的屬性,重構與定義其類型的最佳方式是什麼?
答案#1
檢查(在 JavaScript 中,而不是 TypeScript)被訪問的鍵是否是你想允許的類上直接擁有的鍵——例如 copy 或 paste。然後,TS 將自動推斷這種訪問是被允許的。
get(name: string): () => void {
if (name === 'copy' || name === 'paste') {
return this[name].bind(this)
}
if (this.extensions[name]) {
return this.extensions[name].bind(this)
}
// default to copy
return this.copy.bind(this);
}
