typescript 返回void的函数的属性名的类型定义

zwghvu4y  于 2023-03-09  发布在  TypeScript
关注(0)|答案(2)|浏览(157)

我目前正在为一个项目编写一个小型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>neverNotifyMethods<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

c3frrgcw

c3frrgcw1#

正如您所注意到的,这确实是因为非void返回函数可以赋值给void返回函数。要解决这个问题,只需检查返回类型 only。这里不要将函数类型作为一个整体进行比较。

type CallMethods<T> = {
  [K in keyof T]: T[K] extends (...args: any[]) => any ? ReturnType<T[K]> extends void ? never : K : never;
}[keyof T];

type NotifyMethods<T> = {
  [K in keyof T]: T[K] extends (...args: any[]) => any ? ReturnType<T[K]> extends void ? K : never : never;
}[keyof T];

使用extends将类型与void进行比较不会有此行为。

type Y = number extends void ? true : false;
//   ^? false

如果函数的返回类型可以为null(包括null或undefined),也可以这样做。
Playground

1bqhqjot

1bqhqjot2#

你可以这样写(见操场)

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检查。这个解决方案的缺点是nullundefined的返回类型也会被归类为NotifyMethods,但我目前找不到其他方法。

相关问题