Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript function parameter type based on another parameter

Tags:

typescript

I'll try my best in describing our case, as I have no idea how to title this.

We have a package, which handles requesting our services/cloud functions (if for example service A needs something done by service B, it uses this package). This package exposes a function to call each service (for example for service auth, there would be a auth function exposed. We have a definition of available endpoints for each service and as this grows, it's harder to maintain since we were unable to figure out a way to type the parameters for the requests.

What I wanted to do, is simply have another type which would contain the parameter types for each endpoint of each service. For example we have endpoint called getEmail, which would return email of a user and requires an id parameter. Type params type would look like this:

type Params = {
  getEmail: {
    id: number;
  }
}

Very simplified version of the code:

type FunctionName = 'foo' | 'bar' | 'baz';

type FunctionParams = {
  foo: {
    myVar: number;
  };
  bar: {
    myVar: string;
  };
  baz: Record<string, number>;
};

declare const sendRequest: (...args: any[]) => any;

const callFunction = (
  fn: FunctionName,
  params: FunctionParams[typeof fn],
  //                     ^^^^^^^^^ What should I put here?
) => {
  sendRequest(fn, params);
};

callFunction('foo', {
  myVar: 'this should fail',
  // This is allowed, as the type of the second parameter is:
  // { myVar: number; } | { myVar: string; } | Record<string, number>) => void
  // I want it to be { myVar: number; }
});
like image 292
T. Kallup Avatar asked Nov 28 '25 22:11

T. Kallup


1 Answers

You want to use generics! You can parameterize callFunction to bind fn to a specific string, and then use this to index FunctionParams:

function callFunction<T extends FunctionName>(
  fn: T,
  params: FunctionParams[T],
) {
  sendRequest(fn, params);
};

callFunction('foo', {
  myVar: 'this should fail', //BOOM!
});

Also, don't waste energy maintaining types. FunctionName can be as easy as

type FunctionName = keyof FunctionParams

with that, every time you add new params, FunctionName gets updated. See also this playground

like image 136
ddprrt Avatar answered Nov 30 '25 11:11

ddprrt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!