在 TypeScript 中将函数作为参数传递

要将函数键入为参数,请键入函数的参数列表及其返回值,例如 doMath: (a: number, b: number) => number。 如果函数的定义变得太繁琐,将函数类型提取到类型别名中。

function wrapper(
  a: number,
  b: number,
  // 👇️ function parameter
  doMath: (a: number, b: number) => number,
) {
  return doMath(a, b);
}

// 👇️ Define a function that matches
// expected parameter type
function sum(a: number, b: number) {
  return a + b;
}

console.log(wrapper(10, 20, sum)); // 👉️ 30

// 👇️ Define a function that matches
// expected parameter type
function multiply(a: number, b: number) {
  return a * b;
}

console.log(wrapper(10, 20, multiply)); // 👉️ 200

我们创建了一个带有 3 个参数的函数 – 2 个数字和一个函数。

包装函数使用数字调用传入的函数并返回结果。

包装函数需要一个函数参数,该参数将 2 个数字作为参数并返回一个数字。

sum 和 multiply 函数符合预期的类型,因为它们都将 2 个数字作为参数并返回一个数字。

如果我们的函数定义变得太繁琐,我们可以将函数类型提取到类型别名中。

type LogFunction = ({
  name,
  country,
}: {
  name: string;
  country: string;
}) => void;

function wrapper(
  obj: { name: string; country: string }, logger: LogFunction
) {
  logger(obj);
}

const logger: LogFunction = (obj) => {
  console.log(obj);
};

wrapper({ name: 'Tom', country: 'Chile' }, logger);

我们为一个函数定义了一个类型别名,它接受一个对象作为参数并且不返回一个值。

请注意 ,在键入包装函数和定义记录器函数时重用了类型别名。

如果我们已经定义了将作为参数传递的函数,请在键入包装函数的参数列表时使用 typeof 运算符来推断其类型。

const sum = (a: number, b: number): number => {
  return a + b;
};

function wrapper(a: number, b: number, doMath: typeof sum) {
  return doMath(a, b);
}

console.log(wrapper(10, 15, sum)); // 👉️ 25

因为我们已经声明了 sum 函数,所以我们不必在包装函数的参数列表中键入它。

typeof 运算符可用于引用特定函数的类型。

如果我们尝试传递与预期类型不匹配的函数参数,则会出现错误。

const sum = (a: number, b: number): number => {
  return a + b;
};

function wrapper(a: number, b: number, doMath: typeof sum) {
  return doMath(a, b);
}

console.log(wrapper(10, 15, sum)); // 👉️ 25

function test() {}

// ⛔️ Error: Argument of type '() => void' is not
// assignable to parameter of type
// '(a: number, b: number) => number'.
console.log(wrapper(10, 15, test)); // 👉️ 25

我们传递给包装函数的函数参数与预期类型不匹配,因此类型检查器抛出错误。