[英]Filter on keyof type parameter in typescript
無需了解React,只需了解一些背景知識:在我的用例中,我想使用自定義的Higher Order Component來放大用戶指定的React.ComponentClass。 為此,我希望用戶也向我發送我的高階組件將注入的特定道具的名稱列表。 可以這樣做:
function listToComponentProps<TComponentProps, TKey = keyof TComponentProps>(props: Array<TKey>) {
// Logic here, not important for the example
}
interface TestProps {a: number, b: Function, c: () => number}
listToComponentProps<TestProps>(['a', 'b', 'c'])
keyof
關鍵字為我處理約束。 listToComponentProps<TestProps>
示例輸入為
['b']
, ['b', 'c']
, ['c']
['a']
, ['a', 'b']
, ['a', 'b', 'c']
(a是數字,不是函數) ['d']
, ['d', 'c']
(d不屬於接口TestProps
問題是,我要限制的props
參數不僅是關鍵TComponentProps
,而且這樣的鍵,在對應類型TComponentProps
是Function
(使得'a'
將是由編譯器的打字原稿檢測到一個無效選項)。 一個人怎么能完成這樣的任務?
您可以這樣做:
const listToComponentProps = <
TComponent extends {[P in TKey]: Function },
TKey extends string = keyof TComponent>
(props: TKey[]) => { /* ... */ };
interface TestProps {a: number, b: Function, c: () => number}
const result = listToComponentProps<TestProps>(['a', 'b', 'c']) // Type error
這導致類型錯誤:
Type 'TestProps' does not satisfy the constraint '{ a: Function; b: Function; c: Function; }'.
Types of property 'a' are incompatible.
Type 'number' is not assignable to type 'Function'.
不幸的是,這種使用默認參數的TComponent
最終限制了我們的TComponent
僅具有Function
屬性。 當您真正想要傳遞類似listToComponentProps<TestProps>(['b', 'c'])
,該內容應該是有效的,您將需要顯式填寫第二個類型參數,即listToComponentProps<TestProps, 'b' | 'c'>(['b', 'c'])
listToComponentProps<TestProps, 'b' | 'c'>(['b', 'c'])
。
你真正想要的是不具有缺省參數TKey
,而是用於一般推理,以顆粒狀:在一個類型參數列表, 可以推斷出所有參數(例如TKey
,這可以從傳遞的數組推斷) 應推斷,即使必須手動指定一些(在這種情況下為TComponent
)。 TypeScript目前無法以這種方式工作,所以我們是SOL。
在TypeScript問題跟蹤器上有很多與此有關的未解決問題,您可以去查找它們並臭氣熏天。
如果良好的推理對您而言比嚴格保留運行時特征更為重要,則可以添加一個虛擬參數來分離兩個類型參數的推理:
const listToComponentProps =
<TKey extends string>
(props: TKey[]) =>
<TComponent extends {[P in TKey]: Function }>
() => { /* ... */ };
interface TestProps { a: number, b: Function, c: () => number }
const result = listToComponentProps(['a', 'b', 'c'])<TestProps>() // Type error
const result2 = listToComponentProps(['b', 'c'])<TestProps>() // OK
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.