Мы рассматриваем параметры, типы функций, «это» и многое другое.
Flow - это программа проверки типов от Facebook для проверки типов данных JavaScript. Он имеет множество встроенных типов данных, которые мы можем использовать для аннотирования типов переменных и параметров функций.
В этой части мы рассмотрим другие свойства функций Flow, включая стрелочные функции, типы функций и многое другое.
Стрелочные функции
Стрелочные функции - это функции, которые не имеют другого значения this
внутри функции.
Мы можем добавлять аннотации типов к функциям стрелок, как и к любой другой функции в Flow. Например, мы можем написать:
const foo = (str: string, bool?: boolean, ...nums: Array<number>): void => { console.log(nums); }
Тип функции
Мы можем указать типы параметров и вернуть тип функции как аннотацию собственного типа. Это называется типом функции.
Аннотацию типа можно записать следующим образом:
const foo: (str: string, bool?: boolean, ...nums: Array<number>) => void = (str: string, bool?: boolean, ...nums: Array<number>): void => { console.log(nums); }
В приведенном выше коде код…
(str: string, bool?: boolean, ...nums: Array<number>) => void
… - аннотация типа функции foo
. Он указывает, что первый аргумент - это строка, второй - необязательное логическое значение, а остальные - числа. Кроме того, тип возвращаемого значения - void
, как указано после жирной стрелки.
Аннотации типов функций удобны для таких вещей, как функции обратного вызова:
const fn = (callback: (a: number, b: number) => number) => { }
Параметры функции
К параметрам функции можно добавить аннотацию типа, добавив двоеточие после имени параметра, а затем аннотацию типа параметра.
Например, мы можем написать:
function method(a: string, b: boolean) { }
Затем a
принимает строку, а b
принимает логическое значение.
Дополнительные параметры
Мы можем добавить необязательные параметры, добавив вопросительный знак после имени параметра.
Например, мы можем написать:
function foo(optionalString?: string) { }
Затем мы можем передать undefined
, ничего или string
в foo
:
foo(); foo(undefined); foo("string");
Передача чего-либо еще приведет к ошибке. Например, написание…
foo(null);
… Приведет к ошибке, поскольку это не string
, ничего или undefined
.
Остальные параметры
С помощью оператора rest мы можем передать в функцию любое количество аргументов. Если количество аргументов больше, чем количество фиксированных параметров, тогда оператор rest сохранит другие аргументы в массиве.
Например, мы можем написать:
function foo(a: number, ...args: Array<number>) { console.log(args); }
Затем, когда мы называем это следующим образом ...
foo(1,2,3);
… Мы получим [2,3]
как значение args
, поскольку оператор rest, который работает с args
, отправляет значение, выходящее за пределы первых аргументов, в параметр args
.
В приведенном выше коде мы также указали, что args
- это массив чисел, поэтому передача чего-либо приведет к ошибке.
Аннотации типа должны быть типа Array
, поскольку в JavaScript аргументы оператора rest всегда хранятся в массиве.
Тип возврата функции
Мы можем указать тип возвращаемого значения функции, добавив аннотацию типа после списка параметров. Например, если мы хотим определить функцию, возвращающую строку, мы можем написать следующее, чтобы создать функцию, возвращающую строку:
function foo(): string { return 'foo'; }
Если для функции определен тип возвращаемого значения, он должен возвращать один и тот же тип данных во всех ветвях кода. Например, если мы напишем…
function foo(): string { if (Math.random() > 0.5){ return 'foo'; } }
… Это приведет к ошибке, поскольку foo
не всегда возвращает строку. Чтобы исправить это, мы можем написать:
function foo(): string { if (Math.random() > 0.5){ return 'foo'; } return 'bar'; }
Затем все ветви возвращают строку, которую Flow принимает как действительную.
async
функции всегда возвращают обещание, поэтому аннотация возвращаемого типа должна быть обещанием, если мы хотим его включить.
Например, мы должны написать что-то вроде:
async function foo(): Promise<string> { return 'foo'; }
Ценность этого
Для функций, отличных от стрелочных, значение this
изменяется в зависимости от контекста функции. На верхнем уровне кода функции this
примет значение функции.
В Flow мы не аннотируем значение this
, и мы должны позволить типу выводиться из любого контекста, с которым мы вызываем функцию.
Например, если мы вызываем функцию foo
с числом, как показано ниже…
function foo() { return this; } let num: number = foo.call(1);
… Тогда this
будет числом.
Предикатные функции
В Flow мы можем пометить функцию как функцию-предикат с помощью ключевого слова %checks
. Функция предиката - это функция, которая проверяет условие.
Мы можем определить его, написав следующий код:
function areStrings(a, b): boolean %checks { return typeof a === 'string' && typeof b === 'string'; }
Затем мы можем использовать его, как в следующем коде:
function foo(a, b): string { if (areStrings(a, b)){ return a + b; } return ''; }
Мы также можем вызывать функции предиката в других функциях предиката. Например, мы можем переписать предыдущий пример следующим образом:
function isString(a): boolean %checks { return typeof a === 'string' } function areStrings(a, b): boolean %checks { return isString(a) && isString(b); } function foo(a, b): string { if (areStrings(a, b)){ return a + b; } return ''; }
Вызываемые объекты
Мы можем ввести вызываемый объект. Например, мы можем написать:
type CallableObject = { (string, string): string, foo: string }; function concat(x, y) { return x + y; } concat.foo = "hello world"; (concat: CallableObject);
Чтобы объект считался типом CallableObject
, мы должны определить его как функцию с требуемой сигнатурой и типом возвращаемого значения. Затем мы должны добавить необходимое свойство foo
.
Function
Тип
Мы можем указать более гибкий тип, используя (...args: Array<any>) => any
для функций. Таким образом, функция может иметь любую подпись и возвращать что угодно. Например, мы можем написать:
function foo(fn: (...args: Array<any>) => any){ return fn(); }
Затем мы можем передать любую функцию в качестве функции обратного вызова foo
:
foo((a) => true); foo((a , b) => a + b);
Мы можем добавлять аннотации типов к параметрам и возвращать тип функции. Кроме того, мы можем иметь аннотацию типа для самой функции, указав подпись и тип возвращаемого значения.
Кроме того, мы можем указать типы функций-предикатов с помощью ключевого слова %check
. Мы также можем использовать остальные параметры с Flow. Остальной параметр должен иметь тип массива. Для async
функций у нас должен быть тип возвращаемого значения Promise
, если мы должны добавить тип возврата.
После имени необязательных параметров должен стоять вопросительный знак.
Остальные правила такие же, как в JavaScript.