Spec-Zone.ru › Flow

Функции

Функциям можно задавать типы параметров (входных данных) и возвращаемого значения (выходных данных).

function concat(a: string, b: string): string {
  return a + b;
}


concat("foo", "bar"); // Works!
concat(true, false);  // Error!

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

[1, 2, 3].map(x => x * x);

Синтаксис функций​

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

Объявления функций​

function func(str: string, bool?: boolean, ...nums: Array<number>): void {
  // ...
}

Стрелочные функции​

let func = (str: string, bool?: boolean, ...nums: Array<number>): void => {
  // ...
};

Типы функций​

type T = (str: string, bool?: boolean, ...nums: Array<number>) => void;

При желании можно также опустить имена параметров.

type T = (string, boolean | void, Array<number>) => void;

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

function func(callback: (error: Error | null, value: string | null) => void) {
  // ...
}

Аргументы типов​

Функции могут иметь аргументы типов:

function f<T>(x: T): Array<T> {
  return [x];
}


const g = <T>(x: T): Array<T> => [x];


type H = <T>(T) => Array<T>;

Параметры функций​

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

function func(param1: string, param2: boolean) {
  // ...
}

Необязательные параметры​

Параметры также можно сделать необязательными: для этого добавьте вопросительный знак ? после имени параметра и перед двоеточием :.

function func(optionalValue?: string) {
  // ...
}

Необязательные параметры допускают отсутствие значения, undefined или значения соответствующего типа. Но они не допускают null.

function func(optionalValue?: string) {
  // ...
}


func();          // Works.
func(undefined); // Works.
func("string");  // Works.


func(null);      // Error!

Остаточные параметры​

JavaScript также поддерживает остаточные параметры — параметры, собирающие массив аргументов в конце списка параметров. Перед ними ставится многоточие ....

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

function func(...args: Array<number>) {
  // ...
}

В остаточный параметр можно передать любое количество аргументов.

function func(...args: Array<number>) {
  // ...
}


func();        // Works.
func(1);       // Works.
func(1, 2);    // Works.
func(1, 2, 3); // Works.

Примечание. Если вы добавляете аннотацию типа к остаточному параметру, он должен иметь тип, подобный массиву (например, Array<T>, ReadonlyArray<T> или тип кортежа).

this параметр​

Каждый вызов функции в JavaScript выполняется в специальном контексте с именем this. Flow позволяет аннотировать тип этого контекста, добавив специальный параметр в начало списка параметров функции:

type Counter = {
  x: number,
  getX: (this: Counter) => number,
};


function getX(this: Counter): number {
  return this.x;
}


const counter: Counter = {x: 42, getX};
const num: number = counter.getX();
const str: string = counter.getX(); // Error!

Контекст определяется объектом-получателем вызова. В методах, привязанных к определённому объекту-получателю, call, apply и bind могут повторно указывать только на тот же объект-получатель — см. раздел Повторная привязка this.

Этот параметр не влияет на время выполнения и удаляется вместе с типами при преобразовании Flow в JavaScript. Если параметр this присутствует, он всегда должен стоять в самом начале списка параметров функции и иметь аннотацию. Кроме того, стрелочные функции не могут иметь аннотацию параметра this, поскольку такие функции привязывают параметр this в месте определения, а не в месте вызова.

Если явный параметр this не указан, Flow попытается вывести его тип на основе использования. Если this не упоминается в теле функции, Flow выведет unknown для параметра this.

Возвращаемые значения функций​

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

function func(): number {
  return 1;
}

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

function func(): boolean { // Error
  if (Math.random() > 0.5) {
    return true;
  }
}

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

async function func(): Promise<number> {
  return 123;
}

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

function isString(x: unknown): x is string {
  return typeof x === 'string';
}

Вызываемые объекты​

Функции со статическими свойствами можно типизировать как вызываемые объекты:

type CallableObj = {
  (number, number): number,
  bar: string,
  ...
};


function add(x: number, y: number) {
  return x + y;
}


add.bar = "hello world";


add as CallableObj;

У вызываемых объектов также может быть несколько сигнатур вызова. Функция, присвоенная типу с несколькими сигнатурами, должна соответствовать каждой из них:

type Formatter = {
  (value: string): string,
  (value: number): string,
  ...
};


const format: Formatter = (value: string | number): string => String(value);


const badFormat: Formatter = (value: number): string => String(value); // Error!

В общем случае свойства можно назначать функциям, если они объявлены как функции или как простые переменные в форме const f = () => .... Свойства должны назначаться в формате f.prop = <expr>; в том же списке инструкций, что и определение функции (то есть не в условном блоке).

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

Если аннотировать переменную обычным типом функции, Flow не выведет дополнительные статические свойства:

type Callback = () => void;


const callback: Callback = () => {};


callback.description = "runs later"; // Error!

Перегруженные функции​

Для определения перегруженных типов функций можно использовать типы-пересечения:

declare const fn:
  & ((x: 'string') => string)
  & ((x: 'number') => number)


const s: string = fn('string');
const n: number = fn('number');

Любая функция​

Если нужно разрешить любую функцию и неважно, какую именно, можно использовать следующий шаблон:

function useCallback<T extends (...ReadonlyArray<empty>) => unknown>(
  callback: T,
  inputs: ?ReadonlyArray<unknown>,
): T {
  return callback;
}
useCallback((x: string) => true); // OK
useCallback((x: number) => [1]); // OK

Для более сложных преобразований можно использовать аргументы типов, чтобы сохранить типы аргументов и возвращаемого значения:

function func<TArgs extends ReadonlyArray<unknown>, TReturn>(
  callback: (...TArgs) => TReturn,
): (boolean, ...TArgs) => Array<TReturn> {
  return (b, ...args): Array<TReturn> => {
    if (b) {
      return [callback(...args)];
    } else {
      return [];
    }
  };
}


const f: (boolean, string, number) => Array<string> =
  func((x: string, y: number) => x.slice(y)); // OK

Тип Function — это просто псевдоним для any, который небезопасен. Запретить его использование в коде можно с помощью правила линтера unclear-type.

См. также​

  • Обобщённые типы — параметризованные типы, используемые с функциями для создания повторно используемого типобезопасного кода
  • Защитники типов — специальные типы возвращаемых значений, уточняющие типы параметров
  • Типы-пересечения — определение перегруженных типов функций
  • Подтипы — принцип работы подтипизации функций (контравариантные параметры, ковариантные возвращаемые значения)

© 2013–present Facebook Inc.
Licensed under the MIT License.
https://flow.org/en/docs/types/functions

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API