【发布时间】:2020-09-11 19:09:28
【问题描述】:
让我们为处理函数定义以下类型:
type Handler<T, U> = (x: T) => U;
然后说有一个库接受处理程序字典(然后以某种方式将数据路由到特定处理程序,这与问题无关):
registerHandlers(handlers: Record<string, Handler<any, any>>) {
...
}
这很好用,我可以例如将文字对象传递给registerHandlers 函数:
registerHandlers({
foo: (x: number) => 'foo',
bar: (x: string) => 42
});
但是,为了使界面更清晰并允许更轻松地对处理程序进行存根和测试,我想定义一个描述我的处理程序的接口:
interface Handlers {
foo: Handler<number, string>;
bar: Handler<string, number>;
}
这种方式很容易定义或覆盖一组推断出所有类型的处理程序(显然我的示例被简化了,我的真实代码具有更复杂的类型,这就是为什么我想为整个集合定义一个清晰的类型处理程序):
const handlers: Handlers = {
foo: x => 'foo',
bar: x => 42
}
但是,当我尝试通过调用registerHandlers(handlers) 将我的界面用作Record<string, Handler<any, any>> 时,它不起作用,即使使用as Record<...> 也不行(除非我通过unknown 进行双重转换,这似乎总是最后的手段):
Index signature is missing in type Handlers
我的Handlers 接口显然是一个具有一组Handler 函数的对象,因此在实践中,它应该匹配相同的Record,但事实并非如此。我想我理解为什么不能保证任意接口与Record 匹配,但是有没有一种很好的方法来定义一个类型,以便它是Record<string, Handler<any, any>> 但仍然声明为每个单独的属性都是正确类型的类型Handler<, >?还是我坚持通过unknown 进行双重转换,存在相关风险(一个简单的错字可能会被忽视等)?
【问题讨论】:
标签: typescript typescript-typings typescript-generics