我目前正在为我正在进行的项目编写一个小型 RPC 库。为了确保一定程度的正确性,我使用 typescript 进行一些类型检查。我的初始实现工作正常,在进行一些重构时,我遇到了一些条件类型的问题。
想法是沿着下面的接口定义一个 RPC 服务,并能够将返回值(调用)的调用与不返回值(通知)的调用分开。
export default interface ExampleService {
add(a: number, b: number): number;
sub(a: number, b: number): number;
log(message: string): void;
}
到目前为止我正在返回 Promises 并且它工作正常,但是将返回类型切换为文字/无效类型不再正确
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"
...
可以这样写(见playground)
export default interface ExampleService {
add(a: number, b: number): number;
sub(a: number, b: number): number;
log(message: string): void;
}
type CallMethods<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => (infer R extends NonNullable<infer Z>) ? K : never;
}[keyof T];
type NotifyMethods<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => (infer R extends NonNullable<infer Z>) ? never : K;
}[keyof T];
type CallMethodsList = CallMethods<ExampleService>;
type NotifyMethodsList = NotifyMethods<ExampleService>;
为了正确检测 void 返回类型,我添加了 NonNullable 检查。这个解决方案的缺点是
null
或 undefined
的返回类型也将归类为 NotifyMethods 但我现在找不到其他方法。