Let's say I have a number of APIs which are all dictionaries of async methods, e.g.:
interface MyApi {
foo(a: string): Promise<number>;
bar(a: number, b: boolean): Promise<string>;
baz(): Promise<void>;
}
interface MyAp2 {
qux(a: string): Promise<void>;
}
And I want to define a type which any such interface (=a dictionary where each property is an async function) implements, but in a way so that interfaces containing properties that are NOT async functions (e.g. {foo: number;}
or {foo(): number}
) would not match.
What could such a type look like?
I tried this:
type Api = {
[name: string]: (...args: any[]) => Promise<any>;
};
But I cannot do
class Something<T extends Api> {
}
new Something<MyApi>();
Due to
TS2344: Type 'MyApi' does not satisfy the constraint 'Api'.
Index signature for type 'string' is missing in type 'MyApi'.
So the problem seems to be that a concrete set of functions does not have a general string index signature.
I managed to get something working like this, but it feels bulky:
type Api<T> = {
[P in keyof T]: (...args: any[]) => Promise<any>;
};
class Something<T extends Api<T>> {
}
Now, new Something<MyApi>()
works, but trying to do new Something<{foo: number;}>()
fails, as intended:
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>'.
Is there a cleaner way of defining a type describing a set of async functions that doesn't have to use the "recursive" syntax T extends Api<T>
, i.e., a simple non-generic type which any interface consisting only of async functions will fulfill?