我目前正在为一个项目编写一个小型RPC库。为了确保一定程度的正确性,我使用typescript做了一些类型检查。我得到了最初的实现工作,而在做一些重构时,我遇到了一些条件类型的问题。
其思想是沿着下面的接口定义RPC服务,并能够将返回值的调用(call)与不返回值的调用(notify)分开。
export default interface ExampleService {
add(a: number, b: number): number;
sub(a: number, b: number): number;
log(message: string): void;
}
到目前为止,我返回的是Promises,它工作得很好,但是将返回类型切换为literal/void,类型就不再正确了
type CallMethods<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => void ? never : K;
}[keyof T];
type NotifyMethods<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => void ? K : never;
}[keyof T];
我期望CallMethods<ExampleServer>
为"add" | "sub"
,NotifyMethods<ExampleService>
为"log"
但是使用这个类型定义,我得到的CallMethods<ExampleService>
是never
,NotifyMethods<ExampleService>
是"add" | "sub" | "notify"
...
我的假设是,它与www.example.com中解释的可替代性有关https://github.com/microsoft/TypeScript/wiki/FAQ#why-are-functions-returning-non-void-assignable-to-function-returning-void
2条答案
按热度按时间c3frrgcw1#
正如您所注意到的,这确实是因为非void返回函数可以赋值给void返回函数。要解决这个问题,只需检查返回类型 only。这里不要将函数类型作为一个整体进行比较。
使用
extends
将类型与void进行比较不会有此行为。如果函数的返回类型可以为null(包括null或undefined),也可以这样做。
Playground
1bqhqjot2#
你可以这样写(见操场)
为了检测void返回类型,我添加了NonNullable检查。这个解决方案的缺点是
null
或undefined
的返回类型也会被归类为NotifyMethods,但我目前找不到其他方法。