假设我有许多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>
,即任何只包含异步函数的接口都可以实现的简单非泛型类型?
1条答案
按热度按时间myzjeezk1#
MyApi
需要使用type
而不是interface
,请参见相关解答和官方解释为了让人们了解,这种行为目前是设计好的。因为接口可以通过额外的声明来扩充,而类型别名不能,所以为类型别名推断隐式索引签名比为接口推断隐式索引签名"更安全"(在那个声明上加了重引号)。但是如果看起来有意义,我们也会考虑为接口这样做
Playground
换句话说:默认情况下,
interfaces
没有索引,而type
您还可以选中my article
请考虑使用
interfaces
而不是types
。interfaces
更安全。如果在不同文件中声明两个同名接口,但这些文件包含import
/export
,则不会合并声明,因为这将是两个不同的模块