[英]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.