TypeScript条件类型问题:区分RPC服务的Call/Notify方法
解决TypeScript条件类型区分RPC Call/Notify方法的问题
问题原因
你遇到的问题本质是TypeScript中函数返回值的可替代性规则:返回void的函数类型是所有函数的超类型。也就是说,任何函数(哪怕它实际返回number、string等具体值)都可以赋值给返回void的函数类型。这就导致你原来的条件判断T[K] extends (...args: any[]) => void会匹配所有方法,不管它实际返回什么。
解决方案
要严格区分返回void和非void的方法,需要用严格类型相等检查替代子类型判断。可以通过将返回值包裹在元组中([R] extends [void])来实现,因为元组的类型比较是严格的,不会触发子类型兼容规则。
修改后的条件类型定义如下:
type CallMethods<T> = { [K in keyof T]: T[K] extends (...args: any[]) => infer R ? [R] extends [void] ? never : K : never; }[keyof T]; type NotifyMethods<T> = { [K in keyof T]: T[K] extends (...args: any[]) => infer R ? [R] extends [void] ? K : never : never; }[keyof T];
验证结果
对于你的ExampleService接口:
export default interface ExampleService { add(a: number, b: number): number; sub(a: number, b: number): number; log(message: string): void; }
CallMethods<ExampleService>会正确推导为"add" | "sub"NotifyMethods<ExampleService>会正确推导为"log"
原理说明
用[R] extends [void]替代直接的R extends void,是因为TypeScript对元组类型的比较是严格类型相等,而不是子类型兼容。这样就能精准识别出那些返回类型确实是void的方法,避免把返回具体值的方法误判为void返回。
内容的提问来源于stack exchange,提问作者Adraen
相关产品推荐
相关产品推荐

