我想鍵入一個函式來檢查它的引數型別是否擴展了型別變數,然后回傳引數。
像這樣:
declare function extendsA<I, X extends I>(argument:X): X
但是當我使用它時,打字稿抱怨該函式需要兩個型別引數。或這個:
declare function extendsB<I, X extends I = I>(argument:X): X
這會回傳錯誤的型別。
游樂場鏈接
如何使 typescript 將型別argument放入型別變數中X,確保它擴展I然后回傳X?
一個用例是:
const recordOfNumberArray = extendsA<{[K: string]: readonly number[]}>({
"hello":[10,200]
} as const); // good
recordOfNumberArray. // with intellisense of all keys
const recordOfNumberArray = extendsA<{[K: string]: readonly number[]}>({
"hello":[10,200,"hi"]
} as const); // should error
uj5u.com熱心網友回復:
啊,您正在嘗試satisfies按照microsoft/TypeScript#7481 中的要求實作所謂的 " " 運算子。那里的想法是您可以撰寫val satisfies Type,如果val不是 type Type,則會出現編譯器錯誤,但它不會擴大 val到 type Type。不幸的是,TypeScript 中尚不存在這樣的運算子,因此您正在求助于解決方法。我要從這里重命名extendsA為satisfies。
因此,您不能輕松地將其實作satisfies為兩個型別引數的單個泛型函式,因為 TypeScript 也缺少microsoft/TypeScript#26242 中要求的部分型別引數推斷。編譯器將從呼叫中推斷出所有型別引數,或者您必須手動指定所有型別引數。正如您所發現的,泛型型別引數默認值不能用于為您提供部分推斷,因為如果您省略引數,您將得到的只是默認值。
相反,解決這個問題的正常方法是重構為一個curried函式,其中該函式只接受手動指定的泛型型別引數,然后它回傳另一個函式,該函式接受要推斷的型別引數。像這樣:
// declare function satisfies<I>(): <X extends I>(argument: X) => X;
function satisfies<I>() {
return <X extends I>(argument: X) => argument
}
因此,您必須像這樣呼叫它,并帶有一個額外的函式呼叫步驟:
satisfies<{ [K: string]: readonly number[] }>()({
"hello": [10, 200]
} as const); // good
這并不美妙,盡管如果您發現自己I多次檢查同一型別,可以減輕痛苦,因為您可以重用部分應用的功能:
const satisfiesRecordOfNumberArray =
satisfies<{ [K: string]: readonly number[] }>();
const recordOfNumberArray = satisfiesRecordOfNumberArray({
"hello": [10, 200]
} as const); // good
recordOfNumberArray.hello // okay
const recordOfNumberArray2 = satisfiesRecordOfNumberArray({
"hello": [10, 200, "hi"]
} as const); // error!
// Type 'readonly [10, 200, "hi"]' is not assignable to type 'readonly number[]'
我能想到的唯一另一種方法是將兩個型別引數保留在一個函式中,I并且X添加一個dummyI型別為的虛擬函式引數I。這可能比柯里化更糟糕,因為它迫使您提供一個型別的虛擬值I,或者假裝:
// declare function satisfies<I, X extends I>(dummyI: I, argument: X): X;
function satisfies<I, X extends I>(dummyI: I, argument: X) { return argument }
const recordOfNumberArray = satisfies(null! as { [K: string]: readonly number[] }, {
"hello": [10, 200]
} as const); // good
const recordOfNumberArray2 = satisfies(null! as { [K: string]: readonly number[] }, {
"hello": [10, 200, "hi"]
} as const); // error!
// Type 'readonly [10, 200, "hi"]' is not assignable to type 'readonly number[]'
那行得通,但現在satisfies<I>()(val)你有satisfies(null! as I, val). 正如我所說,可能更糟,盡管它是主觀的。理想情況下,您不需要任何函式呼叫,并且會有一個內置的satisfies運算子。如果沒有內置運算子,從一個函式呼叫到兩個函式呼叫的跳轉似乎并不比從零到一的跳轉差多少。
Playground 代碼鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/409686.html
標籤:
下一篇:基于prop的動態方法簽名?
