typescript 为方法字典定义超类型

iyzzxitl  于 2023-01-21  发布在  TypeScript
关注(0)|答案(1)|浏览(119)

假设我有许多API,它们都是异步方法的字典,例如:

interface MyApi {
  foo(a: string): Promise<number>;
  bar(a: number, b: boolean): Promise<string>;
  baz(): Promise<void>;
}

interface MyAp2 {
  qux(a: string): Promise<void>;
}

我想定义一个类型,任何这样的接口(=一个字典,其中每个属性都是一个异步函数)都可以实现,但是在某种程度上,包含非异步函数属性的接口(例如{foo: number;}{foo(): number})不会匹配。
我试过这个:

type Api = {
  [name: string]: (...args: any[]) => Promise<any>;
};

但我不能

class Something<T extends Api> {
}

new Something<MyApi>();

由于

TS2344: Type 'MyApi' does not satisfy the constraint 'Api'.   
  Index signature for type 'string' is missing in type 'MyApi'.

因此问题似乎是一组具体的函数没有通用的字符串索引签名。
我想办法弄了个像这样的东西,但感觉很笨重:

type Api<T> = {
  [P in keyof T]: (...args: any[]) => Promise<any>;
};

class Something<T extends Api<T>> {
}

现在,new Something<MyApi>()可以正常工作,但是尝试执行new Something<{foo: number;}>()失败了,正如预期的那样:🥳

TS2344: Type '{ foo: number; }' does not satisfy the constraint 'Api<"foo">'.   
  Types of property 'foo' are incompatible.     
    Type 'number' is not assignable to type '(...args: any[]) => Promise<any>'.

有没有一种更干净的方法来定义描述一组异步函数的类型,而不必使用"递归"语法T extends Api<T>,即任何只包含异步函数的接口都可以实现的简单非泛型类型?

myzjeezk

myzjeezk1#

MyApi需要使用type而不是interface,请参见相关解答和官方解释
为了让人们了解,这种行为目前是设计好的。因为接口可以通过额外的声明来扩充,而类型别名不能,所以为类型别名推断隐式索引签名比为接口推断隐式索引签名"更安全"(在那个声明上加了重引号)。但是如果看起来有意义,我们也会考虑为接口这样做

type MyApi = {                              // CHANGE IS HERE
    foo(a: string): Promise<number>;
    bar(a: number, b: boolean): Promise<string>;
    baz(): Promise<void>;
}

interface MyAp2 {
    qux(a: string): Promise<void>;
}

type Api = {
    [name: string]: (...args: any[]) => Promise<any>;
};

class Something<T extends Api> {
}

new Something<MyApi>(); // ok

Playground
换句话说:默认情况下,interfaces没有索引,而type
您还可以选中my article
请考虑使用interfaces而不是typesinterfaces更安全。如果在不同文件中声明两个同名接口,但这些文件包含import/export,则不会合并声明,因为这将是两个不同的模块

相关问题