确保作为泛型传递的接口中的每个函数都是异步的

时间:2019-04-26 23:37:45

标签: typescript

假设我有一个采用通用类的抽象类

export abstract class RegisterableClass<InstanceType>

和下面的实现者:

class UserService extends RegisterableClass<IUserService> implements IUserService {
  someConstant: 42,
  async getAllUsers: (): User[] => {...}
}

具有如下界面:

interface IUserService {
  someConstant: number;
  getAllUsers: () => Promise<User[]>;
}

在这种情况下,我想确保传递的泛型IUserService all 异步的。

我可以使用TypeScript静态地执行此操作吗?

也许正在使用Extract<keyof IUserService, Function>?然后将其传递给某些东西?

也就是说,如果您尝试extend RegisterableClass并将其传递给泛型,而不是所有函数都异步,则打字稿将无法编译

1 个答案:

答案 0 :(得分:3)

如果我正确理解,您希望constrain the type parameter传递给RegisterableClass的方法都是异步的(意味着它们返回promise)。

如果是这样,您可以这样实现:

type AllMethodsAreAsync<I> = {
    [K in keyof I]: I[K] extends (...args: any) => infer R ?
    R extends Promise<any> ? I[K] : (...args: any) => Promise<R> :
    I[K]
}

export abstract class RegisterableClass<I extends AllMethodsAreAsync<I>> {
    // ... something involving I, hopefully
}

如果AllMethodsAreAsync<I>是对象类型,其函数值属性返回promise,则类型函数I将等效于I。但是,如果I具有任何不返回诺言的函数值属性,则AllMethodsAreAsync<I>的相应属性将被更改为改为返回诺言。

然后,如果I extends AllMethodsAreAsync<I>通过通用约束,那就太好了。否则,您会收到一条错误消息,告诉您I中的确切内容不起作用。像这样:

// adding this so standalone example works
type User = { u: string }; 

interface IOkayService {
    someConstant: number;
    getAllUsers(): Promise<User[]>;
}

type OkayService = RegisterableClass<IOkayService>; // okay

interface IBadService {
    someConstant: number;
    getAllUsers(): Promise<User[]>;
    getSomethingSynchronously(x: string): number;
}

type BadService = RegisterableClass<IBadService>; // error!
//                                  ~~~~~~~~~~~
// Type 'IBadService' does not satisfy the constraint 'AllMethodsAreAsync<IBadService>'.
// Types of property 'getSomethingSynchronously' are incompatible.
// Type '(x: string) => number' is not assignable to type '(...args: any) => Promise<number>'.
// Type 'number' is not assignable to type 'Promise<number>'.

Playground link

那是您想要的吗?希望能有所帮助;祝你好运!