簡體   English   中英

Typescript 除 function 之外的任何類型的通用類型

[英]Typescript generic type for anything but a function

structuredClonelodash.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)

https://www.typescriptlang.org/play?ts=4.9.0-dev.20221003&ssl=15&ssc=2&pln=1&pc=1#code/MYGwhgzhAEAqCmEAuBvAUNT1QHsB28AjABQCU6Wl0ATvEgK7V7Yj7wCCeAnkgBYCWeAOYAhekgBi9PMCT98JPvwikMWAL5rMuAgCYyFKploMmLNpx4DhYydNny8+pSq3RNmtADN7c-OYJLJRtxKRk-PEIAHlgAPmIcACMAK3hZAC5oAFEAD1B6ABN4GIAaaBQAbQBreC5M5GpBIQAfPHoAW0T4amaILk6cEABdTLBuMrAAB0mQOugxrjLgMBAQUe51WNJM2ENjOkZmBvpZRngCgGFWAgSUtKRSTx9wxwCObmDRUN9HXRj4pKpDLZPIgQrFWBlMIOfBbHZ7GgHMzHU60S7XeC3IEPNDqIA

有沒有什么辦法解決這一問題?

謝謝

如果 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 實例類型的某種未知類型)。 編譯器不知道如何驗證thisExclude<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屬性的任何對象。 我們擔心那些嗎? 我們是否可能遇到具有名為applycall的屬性的非函數對象? 如果是這樣,我們可以添加更多的部分。 也許我們想添加沒有bind屬性的對象。 或具有bindcallapply屬性但其中每個屬性本身都是基元的對象,如{ 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.

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