Typescript: Как определить тип для обратного вызова функции (как любой тип функции, не универсальный), используемый в параметре метода


313

В настоящее время у меня есть определение типа как:

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

Мне нужно что-то вроде:

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

но 2-й не принимается.

Ответы:


285

Глобальный тип Functionслужит этой цели.

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


27
эта вещь отсутствует в основных типах
Yogesh

13
Это не базовый тип, потому что вы должны определить свои аргументы и возвращаемые значения. что-то вроде обратного вызова: (номер: номер) => void; гораздо полезнее для проверки типов, чем callback: function; было бы.
17

@kpup Чтобы было ясно, вы говорите, что не должны использовать заглавную F, Functionкак показано в первой строке этого ответа, и () => voidпредпочитаете второй абзац (с использованием типа или того, что соответствует варианту использования)?
Раффин

2
FWIW, документы по типам функций доступны здесь
imjared

192

Typescript из v1.4 имеет typeключевое слово, которое объявляет псевдоним типа (аналогично a typedefв C / C ++). Вы можете объявить свой тип обратного вызова таким образом:

type CallbackFunction = () => void;

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

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

Тогда вы можете сказать, например,

let callback: CallbackFunctionVariadic = function(...args: any[]) {
  // do some stuff
};

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

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

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

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

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

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


1
Между чем Functionи (...args: any[]) => anyчто предпочтительнее?
ахонг

@ahong: Лично я предпочел бы последнее, поскольку оно обеспечивает подпись ... обычно. ...args: any[]не очень полезно
Эд С.

type CallbackFunctionSomeVariadic = (arg1: string, arg2: number, ...args: any[]) => void;что я искал, ты.
19

61

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

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

34

Вот пример функции, которая принимает обратный вызов

const sqk = (x: number, callback: ((_: number) => number)): number => {
  // callback will receive a number and expected to return a number
  return callback (x * x);
}

// here our callback will receive a number
sqk(5, function(x) {
  console.log(x); // 25
  return x;       // we must return a number here
});

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

const sqk = (x: number, callback: ((_: number) => void)): void => {
  // callback will receive a number, we don't care what it returns
  callback (x * x);
}

// here our callback will receive a number
sqk(5, function(x) {
  console.log(x); // 25
  // void
});

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

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

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

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

// danger!! don't do this
const sqk = (x: number, callback: ((number) => number)): number

Это допустимый TypeScript, но он будет интерпретирован как ...

// watch out! typescript will think it means ...
const sqk = (x: number, callback: ((number: any) => number)): number

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

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


32

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

  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;

}

10

Существует четыре типа абстрактных функций, вы можете использовать их отдельно, когда знаете, что ваша функция будет принимать аргумент (ы) или нет, будет возвращать данные или нет.

export declare type fEmptyVoid = () => void;
export declare type fEmptyReturn = () => any;
export declare type fArgVoid = (...args: any[]) => void;
export declare type fArgReturn = (...args: any[]) => any;

как это:

public isValid: fEmptyReturn = (): boolean => true;
public setStatus: fArgVoid = (status: boolean): void => this.status = status;

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

export declare type fFunction = fEmptyVoid | fEmptyReturn | fArgVoid | fArgReturn;

тогда используйте это как:

public isValid: fFunction = (): boolean => true;
public setStatus: fFunction = (status: boolean): void => this.status = status;

В приведенном выше примере все правильно. Но приведенный ниже пример использования некорректен с точки зрения большинства редакторов кода.

// you can call this function with any type of function as argument
public callArgument(callback: fFunction) {

    // but you will get editor error if call callback argument like this
    callback();
}

Правильный вызов для редакторов выглядит так:

public callArgument(callback: fFunction) {

    // pay attention in this part, for fix editor(s) error
    (callback as fFunction)();
}

2

Typescript: Как определить тип для функции обратного вызова, используемого в параметре метода ?

Вы можете объявить обратный вызов как 1) свойство функции или 2) метод :

interface ParamFnProp {
    callback: (a: Animal) => void; // function property
}

interface ParamMethod {
    callback(a: Animal): void; // method
}

Существует важная разница в типизации, начиная с TS 2.6 :

Вы получаете более сильные («звуковые») типы в режиме --strictили --strictFunctionTypes, когда объявляется свойство функции . Давайте возьмем пример:

const animalCallback = (a: Animal): void => { } // Animal is the base type for Dog
const dogCallback = (d: Dog): void => { } 
// function property variant
const param11: ParamFnProp = { callback: dogCallback } // error: not assignable
const param12: ParamFnProp = { callback: animalCallback } // works

// method variant
const param2: ParamMethod = { callback: dogCallback } // now it works again ...

Технически говоря , методы являются бивариантными, а свойства функций контравариантными в своих аргументах strictFunctionTypes. Методы все еще проверены более допустимо (даже если не звук), чтобы быть немного более практичным в комбинации со встроенными типами какArray .

Резюме

  • Существует различие типов между свойством функции и объявлением метода
  • Выберите свойство функции для более сильных типов, если это возможно

Пример кода игровой площадки

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.