I have an object containing one or more PreparedStatement
. I need to generalize the type definition for such object. Is it possible to represent that?
type PreparedQuery<Input, Result> = {
input: Input;
result: Result;
};
type Query = {
[Key in string]: PreparedQuery<Input, Result>;
};
Each value of the Query
type of object would be PreparedQuery
but with different Input
and/or Result
. The main goal is to write a function that will take a this object and return a new object that will have the type (Query
-> GeneratedQueries
):
type GeneratedQueries = {
[Key in string]: <Input, Result>(input: Input) => Promise<Result>;
}
So, how do define/represent this Query
type than can have any type of for its generic arguments?
CodePudding user response:
Would this suffice?
type Input='x' |'y' | 'z'
type Result ='a' |'b' | 'z'
type PreparedQuery<Input, Result> = {
input: Input;
result: Result;
};
type Query<I extends Input, R extends Result> = {
[Key in string]: PreparedQuery<I, R>;
};
type GeneratedQueries = {
[Key in string]: <Input, Result>(input: Input) => Promise<Result>;
}
CodePudding user response:
Here's one approach:
type GeneratedQueries<Q extends { [K in keyof Q]: PreparedQuery<any, any> }> =
{ [K in keyof Q]: (input: Q[K]['input']) => Promise<Q[K]['result']> }
The idea is that we allow the type parameter Q
to be an object type with any property keys whatsoever, and where each property value is of type PreparedQuery<any, any>
. We don't really want to constrain the input and output types to that PreparedQuery
, so we use the any
type as the type arguments.
Then we map over the properties of Q
to produce the functions you want. For each key K
in keyof Q
, we index into the corresponding PreparedQuery
property Q[K]
to get the 'input
and 'result
types.
Let's test it:
interface Foo {
a: { input: string, result: number },
b: { input: Date, result: boolean },
c: { input: HTMLElement, result: string }
}
type GeneratedQueriesForFoo = GeneratedQueries<Foo>
/* type GeneratedQueriesForFoo = {
a: (input: string) => Promise<number>;
b: (input: Date) => Promise<boolean>;
c: (input: HTMLElement) => Promise<string>;
} */
Looks good! Note that we could also have used conditional type inference:
type GeneratedQueries<Q extends { [K in keyof Q]: PreparedQuery<any, any> }> =
{ [K in keyof Q]: Q[K] extends PreparedQuery<infer I, infer R> ?
(input: I) => Promise<R> : never }
which gives the same result.