简体   繁体   English

在打字稿中过滤keyof类型参数

[英]Filter on keyof type parameter in typescript

No need to know React, just some background: in my use case, I want to amplify user specified React.ComponentClass with my custom Higher Order Component. 无需了解React,只需了解一些背景知识:在我的用例中,我想使用自定义的Higher Order Component来放大用户指定的React.ComponentClass。 In order to do so, I want user to also send me list of names of the particular props my Higher Order Component will inject. 为此,我希望用户也向我发送我的高阶组件将注入的特定道具的名称列表。 That would be done like this: 可以这样做:

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'])

The keyof keyword handles the constraint for me. keyof关键字为我处理约束。 Example inputs for listToComponentProps<TestProps> would be listToComponentProps<TestProps>示例输入为

  • valid: ['b'] , ['b', 'c'] , ['c'] 有效: ['b']['b', 'c']['c']
  • invalid 无效
    • ['a'] , ['a', 'b'] , ['a', 'b', 'c'] (a is number, not a function) ['a']['a', 'b']['a', 'b', 'c'] (a是数字,不是函数)
    • ['d'] , ['d', 'c'] (d is not part of the interface TestProps ['d']['d', 'c'] (d不属于接口TestProps

The problem is, I want to restrict the props parameter not only to be key of TComponentProps , but also such key that the corresponding type in TComponentProps is Function (so that 'a' would be an invalid option detected by typescript compiler). 问题是,我要限制的props参数不仅是关键TComponentProps ,而且这样的键,在对应类型TComponentPropsFunction (使得'a'将是由编译器的打字原稿检测到一个无效选项)。 How can one achieve such task? 一个人怎么能完成这样的任务?

You could do it like this: 您可以这样做:

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

This results in the 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'.

Unfortunately this business of having a default parameter ends up constraining our TComponent to have only Function properties. 不幸的是,这种使用默认参数的TComponent最终限制了我们的TComponent仅具有Function属性。 When you genuinely want to pass something like listToComponentProps<TestProps>(['b', 'c']) , which should be valid, you will need to explicitly fill in the second type parameter, ie listToComponentProps<TestProps, 'b' | 'c'>(['b', 'c']) 当您真正想要传递类似listToComponentProps<TestProps>(['b', 'c']) ,该内容应该是有效的,您将需要显式填写第二个类型参数,即listToComponentProps<TestProps, 'b' | 'c'>(['b', 'c']) listToComponentProps<TestProps, 'b' | 'c'>(['b', 'c']) . listToComponentProps<TestProps, 'b' | 'c'>(['b', 'c'])

What you really want is not to have a default parameter for TKey , but rather for generic inference to be granular: in a type parameter list, all parameters that can be inferred (eg TKey , which can be inferred from the passed array) should be inferred, even if some (in this case, TComponent ) have to be specified manually. 真正想要的是不具有缺省参数TKey ,而是用于一般推理,以颗粒状:在一个类型参数列表, 可以推断出所有参数(例如TKey ,这可以从传递的数组推断) 推断,即使必须手动指定一些(在这种情况下为TComponent )。 TypeScript doesn't work this way today, so we're SOL. TypeScript目前无法以这种方式工作,所以我们是SOL。

There's a bunch of open issues on the TypeScript issue tracker about this, you could go find them and kick up a stink. 在TypeScript问题跟踪器上有很多与此有关的未解决问题,您可以去查找它们并臭气熏天。


If good inference is more important to you than strictly preserving runtime characteristics, you could add a dummy argument to dissociate inference for the two type parameters: 如果良好的推理对您而言比严格保留运行时特征更为重要,则可以添加一个虚拟参数来分离两个类型参数的推理:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM