Determine the return type based upon the argument of a function in TypeScript

Viewed 51

Is it possible in TypeScript to determine the return type of a function based upon its arguments? This would be helpful in case you want to get a subset of properties from e.g. a database query.

Here is an example (https://repl.it/repls/IrresponsibleUnsightlySequences#index.ts) :

type QueryReturnType = {
  a: string;
  b: number;
  c: boolean;
};

const queryFunc = (): QueryReturnType => {
  return {
    a: 'b',
    b: 1,
    c: true,
  };
};

type Params = {
  [key: string]: keyof QueryReturnType;
};

const takeQuerySubset = (params: Params) => {
  const res: any = {};
  Object.keys(params).map((key) => {
    res[`${key}`] = queryFunc()[params[key]];
  });

  return res;
};

takeQuerySubset({ test1: 'a' }); // { test1: 'b' }

takeQuerySubset({ test2: 'b' }); // { test2: '1' }

takeQuerySubset({ test3: 'b', test4: 'c' }); // { test3: '1', test4: true }

This works, however the type of takeQuerySubset is: (params: Params) => any, while the goal is to get a return type that is based upon the parameters i.e.:

takeQuerySubset({ test1: 'a' }); // return type should be {test1: string}

takeQuerySubset({ test2: 'b' }); // return type should be {test2: number}

takeQuerySubset({ test3: 'b', test4: 'c' }) // return type should be {test3: number, test4: boolean}

So that another function that uses takeQuerySubset can reliably determine what it is going to get returned.

To get rid of the any I tried with generics but no luck so far. Note also that the variables are renamed i.e. a is now called test1, b is test2, and so on.

2 Answers

I think you just want this:

const takeQuerySubset = <T extends Record<string, any>>(params: T): T => {
  const res: any = {};
  Object.keys(params).map((key) => {
    res[`${key}`] = queryFunc()[params[key]];
  });

  return res;
};
Related