[英]Typescript generic type for anything but a function
structuredClone
或lodash.cloneDeep
不能克隆函數。
有沒有辦法從泛型中排除 Function 類型?
我嘗試object: Exclude<T, {[key: string|number|symbol]: any, apply: any, call: any}>
和object: Exclude<T, Function>
,當 object 是作為this
傳入。
function cloneAnythingButFunction1<T>(object: Exclude<T, {[key: string|number|symbol]: any, apply: any, call: any}>): T{
return structuredClone(object)}
function cloneAnythingButFunction2<T>(object: Exclude<T, Function>): T{
return structuredClone(object)
}
// Expect error:
cloneAnythingButFunction1(cloneAnythingButFunction1)
cloneAnythingButFunction2(cloneAnythingButFunction2)
// Expect no error:
class Test{
clone1(){
return cloneAnythingButFunction1(this) // error
}
clone2(){
return cloneAnythingButFunction2(this) // error
}
}
const test = new Test()
cloneAnythingButFunction1(test)
cloneAnythingButFunction2(test)
有沒有什么辦法解決這一問題?
謝謝
如果 TypeScript否定了在(但從未合並自) microsoft/TypeScript#29317中實現的排序類型,那么您可以只寫
// Don't do this, it isn't valid TypeScript:
declare function cloneAnythingButFunction<T extends not Function>(object: T): T;
並完成它。 但是在 TypeScript 中沒有not
,至少從 TypeScript 4.8 開始,所以你不能。
有多種方法可以嘗試模擬/模擬not
。 一種方法是做你正在做的事情:寫一個像循環通用約束一樣的條件類型,你已經在這里完成了:
declare function cloneAnythingButFunction<T>(object: Exclude<T, Function>): T;
這適用於特定類型的參數,例如
cloneAnythingButFunction(123); // okay
cloneAnythingButFunction({ a: 1, b: 2 }); // okay
cloneAnythingButFunction(Test) // error
cloneAnythingButFunction(() => 3) // error
cloneAnythingButFunction(new Test()); // okay
但是當參數本身是泛型類型時,它就會崩潰。 而 class 方法中this
的多態this
類型是隱式泛型類型參數。 (也就是說,它被視為受限於 class 實例類型的某種未知類型)。 編譯器不知道如何驗證this
對Exclude<this, Function>
的可分配性,這是有道理的,因為編譯器不知道如何說Test
的某些子類型可能也不會實現Function
。
您可以通過將其擴展this
特定的超類型來解決它,例如Test
:
class Test {
clone1() {
const thiz: Test = this;
return cloneAnythingButFunction(thiz); // okay
// return type is Test, not this
}
}
另一種近似否定類型的方法是將所有可能類型的集合分割成大部分覆蓋您要否定的事物的補充部分。 我們知道沒有原始類型是函數,所以我們可以從
type NotFunction = string | number | boolean | null | undefined | bigint | ....
然后我們可以開始添加 object 種也不是函數的類型。 可能任何類似數組的類型都不會是 function:
type NotFunction = string | number | boolean | null | undefined | bigint |
readonly any[] | ...
任何沒有定義apply
屬性的 object 也不是 function:
type NotFunction = string | number | boolean | null | undefined | bigint |
readonly any[] | { apply?: never, [k: string]: any } | ...
任何沒有定義call
屬性的 object 也不是 function:
type NotFunction = string | number | boolean | null | undefined | bigint |
readonly any[] | { apply?: never, [k: string]: any } |
{ call?: never, [k: string]: any };
我們應該繼續前進還是停在那里? NotFunction
的上述定義將錯誤分類具有apply
屬性和call
屬性的任何對象。 我們擔心那些嗎? 我們是否可能遇到具有名為apply
和call
的屬性的非函數對象? 如果是這樣,我們可以添加更多的部分。 也許我們想添加沒有bind
屬性的對象。 或具有bind
、 call
和apply
屬性但其中每個屬性本身都是基元的對象,如{ call: string | number |... , apply: string | number |... }
{ call: string | number |... , apply: string | number |... }
{ call: string | number |... , apply: string | number |... }
... 但在某些時候我們應該停下來。 近似於 3.14 對於很多用例來說已經足夠好了,而且通常比近似於 3.141592653589793238462643383 更麻煩。 讓我們只使用上面的定義。
無論如何,現在讓我們嘗試使用NotFunction
代替not Function
:
declare function cloneAnythingButFunction<T extends NotFunction>(object: T): T;
cloneAnythingButFunction(123); // okay
cloneAnythingButFunction({ a: 1, b: 2 });
cloneAnythingButFunction(Test) // error
cloneAnythingButFunction(() => 3) // error
cloneAnythingButFunction(new Test()); // okay
class Test {
clone1() {
return cloneAnythingButFunction(this); // okay
}
}
那些行為符合預期。 仍然有可能將Test
的某些子類型分配給Function
,但我認為編譯器不關心,我們也不關心。
當然我們不關心這個:
cloneAnythingButFunction({apply: "today", call: "1-800-TYP-SCRP"}); // error oh noez
因為如果我們這樣做了,我們就必須在NotFunction
的近似值中添加更多的數字來處理它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.