1

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?

1
  • Does this approach meet your needs? If so I can write up an answer explaining it; if not, what am I missing? Commented Aug 7, 2022 at 18:54

1 Answer 1

1

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.

Playground link to code

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.