為了了解 Proxy 的工作原理,我想嘗試製作一個 Proxied 類,該類可以處理任何屬性名稱,即使是類中不存在的那些,同時仍然保持對舊屬性的訪問。當一個類被代理時,我認為 Typescript 會讓你在本地執行此操作(因為這畢竟是代理用例之一),但我遺憾地發現情況並非如此。當我嘗試做這樣的事情時:
const handler = {
get: (target: any, key: string) => {
return key;
},
set: (target: any, key: string, value: any) => {
console.log(target, key, value);
return true;
}
};
class ProxTest {
private storage: {[key: string]: any} = {};
public a: number;
constructor() {
return new Proxy(this, handler);
}
}
const c = new ProxTest();
c.val = "b"; //Gives error
嘗試訪問時出錯c.val
。我找到了一個“解決方案”,即使用“索引簽名”並將 //@ts-ignore 添加到所有其他屬性。
const handler = {
get: (target: any, key: string) => {
return key;
},
set: (target: any, key: string, value: any) => {
console.log(target, key, value);
return true;
}
};
class ProxTest {
//@ts-ignore
private storage: {[key: string]: any} = {};
//@ts-ignore
public a: number;
[key: string]: any;
constructor() {
return new Proxy(this, handler);
}
}
const c = new ProxTest();
c.val = "b";
這是迄今為止我找到的唯一解決方案,老實說我並不喜歡它。有沒有其他方法可以做到這一點?
需要明確的是,這段代碼只是一般問題的一個例子(不能在代理對像上使用任意命名的屬性),它的形狀或形式與我實際使用的某些代碼沒有任何關係。但是因為這似乎是在打字稿中使用代理時應該能夠做的事情,所以我想找到一個通用的解決方案
所以,根據評論,我誤解了 Proxy 的工作方式,我認為它像 PHP 魔術方法一樣工作(也就是說,只有在嘗試訪問未知屬性時才會觸發 get/set 陷阱),而不是它適用於所有屬性,甚至那些已經存在於對像中的。
我假設打字稿會自動檢測一個代理類,並讓您像代理之前一樣使用該類的正常值,而在嘗試訪問未知屬性時它不會出錯,這可能就是我不能自己做的原因清楚我在問什麼。
默認情況下,當使用 Proxy 時,typescript 會將類型更改為“any”,這當然可以讓您在對像上使用任何類型的屬性而不會出錯,代價是無法直接訪問現有屬性(這是實際上與 javascript 一致,因為當您代理一個類並聲明 get/set 時,一切都會通過這些方法)
所以,我真正想要實現的是有一個代理類,我仍然可以訪問已經存在的屬性,並且 typescript 可以正確推斷已經存在的屬性的類型,同時在嘗試訪問不存在的屬性時仍然沒有錯誤. 我想出了這個解決方案:
interface ProxTestStorage extends ProxTestConstructor {
[key: string]: any;
}
interface ProxTestConstructor {
new(): ProxTestImpl & ProxTestStorage;
}
class ProxTestImpl {
protected storage: {[key: string]: any} = {};
public a: number = 3;
}
const handler = {
get: (target: any, key: string) => {
console.log(target, key);
return Reflect.get(key in target ? target : target.storage, key);
},
set: (target: any, key: string, value: any) => {
console.log(target, key);
return Reflect.set(key in target ? target : target.storage, key, value);
}
};
const ProxTest = ProxTestImpl as any as ProxTestImpl & ProxTestStorage;
const c = new Proxy<typeof ProxTest>(new ProxTest(), handler);
c.val = "b"; //No error, type is any
c.a = 2; //No error, type is number
console.log(c); // ...{a: 2, storage: {val: "b"}}...
當然 get 和 set 需要正確實現才能讓您訪問現有屬性(使用“in”的缺點是屬性需要初始化才能看到,但由於這“只是”理解代理的練習,我是好的)並且它們必須與您的類型的邏輯一致。通過聲明這樣的類型,我在使用 ProxTest 作為類型時必須使用“typeof ProxTest”(與普通類不同),但我想現在這是一個小問題,超出了我的問題範圍。
感謝@jcalz 的耐心:)
Este artigo é coletado da Internet.
Se houver alguma infração, entre em [email protected] Delete.
deixe-me dizer algumas palavras