7

Как определить тип для функции-коллбэка (как любой тип функции, а не универсальный any) в параметре метода

1

У меня есть определение типа, которое выглядит следующим образом:

interface Param {
    title: string;
    callback: any;
}

Мне нужно что-то подобное:

interface Param {
    title: string;
    callback: function;
}

Однако второй вариант не принимает компилятор. Как правильно описать тип для callback, чтобы он был функцией?

5 ответ(ов)

7

Глобальный тип Function выполняет эту задачу.

Кроме того, если вы планируете вызывать этот коллбэк без аргументов и игнорировать его возвращаемое значение, тип () => void подходит для всех функций, которые не принимают аргументов.

3

В TypeScript, начиная с версии 1.4, появился ключевое слово type, которое позволяет объявлять псевдонимы типов, аналогичные typedef в C/C++. Вы можете объявить тип вашей функции обратного вызова следующим образом:

type CallbackFunction = () => void;

Это объявляет функцию, которая не принимает аргументов и ничего не возвращает. Если вам нужна функция, которая может принимать ноль или более аргументов любого типа и ничего не возвращает, то вы можете использовать следующий синтаксис:

type CallbackFunctionVariadic = (...args: any[]) => void;

После этого вы можете, например, сделать так:

let callback: CallbackFunctionVariadic = function(...args: any[]) {
  // выполняем какие-то действия
};

Если вам нужна функция, которая принимает произвольное количество аргументов и может возвращать любой тип (включая void), вы можете объявить так:

type CallbackFunctionVariadicAnyReturn = (...args: any[]) => any;

Также можно указать некоторые обязательные аргументы, а затем набор дополнительных аргументов (например, строку, число и далее произвольное количество дополнительных аргументов) следующим образом:

type CallbackFunctionSomeVariadic =
  (arg1: string, arg2: number, ...args: any[]) => void;

Это может быть полезно, например, для обработчиков событий в EventEmitter.

Функции можно типизировать так строго, как вам нужно, хотя вы можете увлечься этим и столкнуться с комбинаторными проблемами, если попытаетесь все зафиксировать с помощью псевдонима типа.

0

Следуя ответу Райана, я думаю, что интерфейс, который вы ищете, можно определить следующим образом:

interface Param {
    title: string;
    callback: () => void;
}
0

Вы можете определить тип функции в интерфейсе различными способами:

  1. Общий способ:
export interface IParam {
  title: string;
  callback(arg1: number, arg2: number): number;
}
  1. Если вы хотите использовать синтаксис свойств, то:
export interface IParam {
  title: string;
  callback: (arg1: number, arg2: number) => number;
}
  1. Если сначала объявить тип функции, то:
type MyFnType = (arg1: number, arg2: number) => number;

export interface IParam {
  title: string;
  callback: MyFnType;
}

Использование очень просто:

function callingFn(paramInfo: IParam): number {
    let needToCall = true;
    let result = 0;
    if (needToCall) {
        result = paramInfo.callback(1, 2);
    }

    return result;
}
  1. Вы также можете объявить литерал типа функции, что означает, что функция может принимать другую функцию в качестве параметра. Параметрическая функция также может называться колбеком.
export interface IParam {
  title: string;
  callback(lateCallFn?: (arg1: number, arg2: number) => number): number;
}
0

Вот пример функции, которая принимает коллбэк:

const sqk = (x: number, callback: ((_: number) => number)): number => {
  // коллбэк получает число и должен вернуть число
  return callback(x * x);
}

// здесь наш коллбэк будет принимать число
sqk(5, function(x) {
  console.log(x); // 25
  return x;       // здесь мы должны вернуть число
});

Если вас не волнуют возвращаемые значения коллбеков (большинство людей не знает, как эффективно их использовать), вы можете использовать void:

const sqk = (x: number, callback: ((_: number) => void)): void => {
  // коллбэк получает число, нам не важно, что он возвращает
  callback(x * x);
}

// здесь наш коллбэк будет получать число
sqk(5, function(x) {
  console.log(x); // 25
  // void
});

Обратите внимание на сигнатуру, которую я использовал для параметра callback:

const sqk = (x: number, callback: ((_: number) => number)): number

Я бы сказал, что это недостаток TypeScript, потому что мы должны предоставить имя для параметров коллбека. В этом случае, я использовал _, потому что его нельзя использовать внутри функции sqk.

Однако, если вы сделаете так:

// опасно!! не делайте этого
const sqk = (x: number, callback: ((number) => number)): number

Это валидный TypeScript, но его будет неправильно интерпретировать как:

// остерегайтесь! TypeScript будет думать, что это ...
const sqk = (x: number, callback: ((number: any) => number)): number

То есть, TypeScript подумает, что имя параметра число — это number, а подразумеваемый тип — any. Это явно не то, что мы имели в виду, но, увы, так работает TypeScript.

Так что не забудьте указать имена параметров при типизации ваших функций... как бы глупо это ни казалось.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь