无需了解 React,只需一些背景知识:在我的用例中,我想使用我的自定义高阶组件来扩展用户指定的 React.ComponentClass。为此,我希望用户还向我发送我的高阶组件将注入(inject)的特定 Prop 的名称列表。这将像这样完成:
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 不是接口(interface)的一部分TestProps
-
问题是,我想限制 props
参数不仅是TComponentProps
的关键, 也是 TComponentProps
中相应类型的键是Function
(因此 'a'
将是 typescript 编译器检测到的无效选项)。如何完成这样的任务?
最佳答案
你可以这样做:
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
只有Function
特性。当你真的想传递类似 listToComponentProps<TestProps>(['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
关于typescript - 在 typescript 中过滤keyof类型参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47359713/