34

I have a method produce with the following signature:

interface ProduceConditions {
    [key: string]: Function|Promise<any>;
}

produce(conditions: ProduceConditions, input: any): Promise<object>|object;

The thing is that the returned (resolved) object has the same keys as the conditions object.

1

2 Answers 2

38

If I understand what you're asking correctly, your input conditions will be an implementation of ProduceConditions with some set of keys, and the return value (whether or not wrapped in a promise) will have the same keys but with the values all resolved.

In which case, the signature you're looking for would be something like:

produce<T extends ProduceConditions, U extends { [key in keyof T]: any }>(conditions: T, input: any): Promise<U> | U

Here I've used two generic types to represent the input and the output, with the requirement that the input type T meets the definition of ProduceConditions and the output type U has the same keys as T.

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

2 Comments

I can't imagine you want the return value to be generic, given that signature. The caller chooses (or TypeScript infers at the call site) the types of T and U. How could the implementation guarantee that it will return a U? For example: produce<{ dog: () => string }, { cat: number, dog: boolean }>(...)?
@jcalz I assumed they have specific input and output types, but you may be right; in that case, you’d just replace the Us in the output with the T-based definition.
15

If the input is supposed to be an object whose values are functions or promises and the output is an object with those functions called or promises resolved, then you can use mapped types and inference from mapped types to specify that constraint:

type ProduceConditionsMapper<T> = {
  [K in keyof T]: ((input: T[K]) => void) | Promise<T[K]>;
}

declare function produce<T>(conditions: ProduceConditionsMapper<T>, input: any): T;

In action:

declare const func: (x: number) => void;    
declare const prom: Promise<string>;
const produceConditions = {
  cat: func,
  dog: prom
}

const ret = produce(produceConditions, 'hmm');
// inferred as {cat: number; dog: string;}

I'm not sure what the relationship between input and the other types are, but it's likely you could give it a more specific type than any for even better results. Anyway, hope that helps.

1 Comment

Thank you @jcalz for the suggestion. It will take me some time to fully understand your example, as in Typescript context I am a 'noob'. As for the input type - input is any as I have no knowledge about its possible type.

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.