Функции
Функциям можно задавать типы параметров (входных данных) и возвращаемого значения (выходных данных).
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