[英]How to guarantee that passed object key is callable using Typescript?
我正在尝试为特定用例创建一个 React 高阶组件,问题归结为以下几点:
function sample<TObj, P extends keyof TObj, F extends keyof TObj>(
obj: TObj,
prop: P,
setProp: TObj[F] extends (value: TObj[P]) => void ? F : never
) {
obj[setProp](obj[prop]);
}
I want to be able to pass an object, a string which should be a key of that object, and another key of that object but which is required to be a function.
这可以进一步简化为:
function sample2<TObj, F extends keyof TObj>(
obj: TObj,
setProp: TObj[F] extends () => void ? F : never
) {
obj[setProp]();
}
在我看来,因为我使用条件类型,可以保证obj[setProp]
将是 function 但我收到错误:
This expression is not callable.
Type 'unknown' has no call signatures.ts(2349)
如下所示,如果使用不符合要求的键调用 function 将出错。 但同样的要求似乎不适用于 function 内部。
我知道这可以被视为一个 XY 问题,但它让我对是否有办法让这个特定问题正常工作非常感兴趣。
在sample2()
的实现中,类型TObj[F] extends () => void? F: never
TObj[F] extends () => void? F: never
是未解析的条件类型。 也就是说,它是一个条件类型,取决于要解析的当前未指定的泛型类型参数。 在这种情况下,编译器通常不知道如何处理它并将其视为本质上不透明的。 (有关此问题的一些讨论,请参见microsoft/TypeScript#23132 。)特别是它没有意识到TObj[Tobj[F] extends ()=>void? F: never]
TObj[Tobj[F] extends ()=>void? F: never]
最终将不得不解析为()=>void
的某些子类型。
一般来说,除非必要,否则我会完全避免使用条件类型。 编译器可以更轻松地从Record<K, V>
等映射类型中理解和推断:
function sample2<K extends PropertyKey, T extends Record<K, () => void>>(
obj: T,
prop: K
) {
obj[prop]();
}
当你调用它时,它的行为类似:
const obj2 = {
func() { console.log("func") },
prop: 42
};
sample2(obj2, "func"); // okay,
//sample2(obj, "prop"); // error
// ~~~ <-- number is not assignable to ()=>void
编辑:为了解决原始sample()
,我会使用这个定义:
function sample<
PK extends PropertyKey,
FK extends PropertyKey,
T extends Record<PK, any> & Record<FK, (v: T[PK]) => void>
>(
comp: T,
prop: PK,
setProp: FK
) {
comp[setProp](comp[prop]);
}
const obj = {
func(z: number) { console.log("called with " + z) },
prop: 42
}
我认为,这也符合您的意愿:
sample(obj, "prop", "func"); // called with 42
sample(obj, "prop", "prop"); // error!
// ~~~ <-- number not assignable to (v: number)=>void
sample(obj, "func", "func"); // error!
// ~~~ <-- (v: number)=>void not assignable to number
好的,希望有帮助; 祝你好运!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.