基于另一个参数的 Typescript 函数参数类型

T. *_*lup 18 typescript

我会尽力描述我们的案例,因为我不知道如何命名这个案例。

我们有一个包,它处理请求我们的服务/云功能(例如,如果服务 A 需要服务 B 完成某些操作,它就会使用这个包)。该包公开了一个函数来调用每个服务(例如auth,对于 service ,将auth公开一个函数。我们为每个服务定义了可用端点,随着数量的增长,维护变得更加困难,因为我们无法找到一种方法输入请求的参数。

我想做的只是拥有另一种类型,其中包含每个服务的每个端点的参数类型。例如,我们有一个名为 的端点getEmail,它将返回用户的电子邮件并需要一个id参数。类型参数类型看起来像这样:

type Params = {
  getEmail: {
    id: number;
  }
}
Run Code Online (Sandbox Code Playgroud)

代码的非常简化版本:

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; }
});
Run Code Online (Sandbox Code Playgroud)

ddp*_*rrt 25

您想使用泛型!您可以参数化callFunction以绑定fn到特定字符串,然后使用它来索引FunctionParams

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

callFunction('foo', {
  myVar: 'this should fail', //BOOM!
});
Run Code Online (Sandbox Code Playgroud)

另外,不要浪费能源维持类型。FunctionName可以像这样简单

type FunctionName = keyof FunctionParams
Run Code Online (Sandbox Code Playgroud)

这样,每次添加新参数时,FunctionName都会更新。另请参阅这个游乐场