Тип функций в TypeScript
В JavaScript могут быть переменные, хранящие функции. В этом случае TypeScript позволяет нам указать, что эта переменная имеет тип «функция».
Тип функции представляет собой комбинацию типов параметров и типа возвращаемого значения. Эта комбинация называется функции.
Чтобы указать переменной тип функции, нужно в круглых скобках перечислить параметры и их типы, а после стрелки => указать тип возвращаемого значения.
Давайте посмотрим на примере. Объявим какую-нибудь переменную как содержащую функцию:
let func: (x: number, y: number) => number;
Запишем в эту переменную функцию заданного типа:
func = function(a: number, b: number): number < return a + b; >;
Свой тип с функцией
Иногда удобнее объявить отдельный тип, который будет содержать описание параметров и возвращаемого значения функции:
type Func = (x: number, y: number) => number;
Затем можно будет объявлять функции с таким типом.
Давайте для примера объявим функцию, которая складывает два числа:
let func1: Func = function(a: number, b: number): number < return a + b; >;
А теперь объявим функцию, которая умножает два числа:
let func2: Func = function(a: number, b: number): number < return a * b; >;
Практические задачи
Укажите переменной тип функции:
Как получить тип возвращаемого значения функции ts
В javascript функции определяются с помощью ключевого слова function , например:
function add(a, b) < return a + b; >// использование функции let result1 = add(1, 2); // результат 3 let result2 = add("1", "2"); // результат 12
TypeScript также определяет функцию с помощью ключевого слова function , но при этом добавляет дополнительные возможности по работе с функциями. В частности, теперь мы можем определить тип передаваемых параметров и тип возвращаемого значения.
Параметры функции
Функция может иметь параметры, которые указываются после названия функции в скобках через запятую. Через двоеточие после имени параметра указывается его тип:
// определение функции function add(a: number, b: number) < let result = a + b; console.log(result); >// вызов функции add(20, 30); // 50 add(10, 15); //25
Однако поскольку параметры имеют тип number, то при вызове функции
add("1", "2");
компилятор TS выдаст ошибку, так как параметры должны иметь тип number, а не тип string.
При этом функция может не только использовать передаваемые параметры, но и глобальные переменные, определенные во вне:
let koef: number = 1.5; function add(a: number) < let result = a *koef; console.log(result); >add(20); // 30 add(10); //15
Результат функции
Функция может возвращать значение определенного типа, который еще называется типом функции. Возвращаемый тип функции ставится после списка параметров через двоеточие:
function add(a: number, b: number): number < return a + b; >let result = add(1, 2); console.log(result);
В данном случае функция будет возвращать значение типа number .
Если функция ничего не возвращает, то указывается тип void :
function add(a: number, b: number): void < console.log(a + b); >add(10, 20);
В принципе мы можем и не указывать тип, тогда он будет выводиться неявно на основе возвращаемого значения:
function add(a: number, b: number) < return a + b; >let result = add(10, 20);
Необязательные параметры
В typescript при вызове в функцию должно передаваться ровно столько значений, сколько в ней определено параметров:
function getName(firstName: string, lastName: string) < return firstName + " " + lastName; >let name1 = getName("Иван", "Кузнецов"); let name2 = getName("Иван", "Михайлович", "Кузнецов"); //ошибка, много параметров let name3 = getName("Иван"); //ошибка, мало параметров
Чтобы иметь возможность передавать различное число значений в функцию, в TS некоторые параметры можно объявить как необязательные. Необязательные параметры должны быть помечены вопросительным знаком ? . Причем необязательные параметры должны идти после обязательных:
function getName(firstName: string, lastName?: string) < if (lastName) return firstName + " " + lastName; else return firstName; >let name1 = getName("Иван", "Кузнецов"); console.log(name1); // Иван Кузнецов let name2 = getName("Вася"); console.log(name2); // Вася
Во втором случае, когда в функцию передается только имя, второй используемый параметр будет иметь неопределенное значение или «undefined». Поэтому с помощью условной конструкции проверяется наличие значения для этого параметра.
Значения параметров по умолчанию
Параметры позволяют задать начальное значение по умолчанию. И если для такого параметра не передается значение, то он использует значение по умолчанию:
function getName(firstName: string, lastName: string="Иванов") < return firstName + " " + lastName; >let name1 = getName("Иван", "Кузнецов"); console.log(name1); // Иван Кузнецов let name2 = getName("Вася"); console.log(name2); // Вася Иванов
Причем в качестве значения можно передавать результат другого выражения:
function defaultLastName(): string < return "Smith"; >function getName(firstName: string, lastName: string=defaultLastName()) < return firstName + " " + lastName; >let name1 = getName("Tom"); console.log(name1); // Tom Smith
Функции¶
Система типов TypeScript уделяет большое внимание функциям, ведь они являются основными строительными блоками нашей составной системы.
Описание параметров¶
Конечно, вы можете описывать типы параметров функции так же, как вы можете описываете типы других переменных:
1 2 3 4 5
// описание переменной var sampleVariable: bar: number >; // описание параметра функции function foo(sampleParameter: bar: number >) <>
Здесь я использовал встроенные описания типа. Конечно, вы можете использовать интерфейсы и т. д.
Описание типа возврата¶
Вы можете описывать тип того что возвращаете из функции после списка параметров функции тем же стилем, который вы используете для переменной, например, : Foo в следующем примере:
1 2 3 4 5 6 7 8
interface Foo foo: string; > // Тип для описания возвращаемого функцией значения `: Foo` function foo(sample: Foo): Foo return sample; >
Да, я использовал здесь интерфейс, но вы можете использовать другие описания, например, встроенные описания.
Как правило, вам не нужно описывать тип возвращаемого функцией значения, так как он может быть автоматически распознан компилятором.
1 2 3 4 5 6 7
interface Foo foo: string; > function foo(sample: Foo) return sample; // распознан тип возвращаемого значения 'Foo' >
Однако, как правило, рекомендуется добавлять эти описания типов для устранения ошибок, например:
1 2 3 4 5 6
function foo() return fou: 'John Doe' >; // Возможно, вы не сможете найти эту опечатку // `foo`, пока не станет слишком поздно > sendAsJSON(foo());
Если вы не планируете возвращать что-либо из функции, вы можете описать ее как :void , но как правило вы можете опустить :void .
Необязательные параметры¶
Вы можете пометить параметр как необязательный:
1 2 3 4 5 6
function foo(bar: number, bas?: string): void // .. > foo(123); foo(123, 'hello');
В качестве альтернативы вы можете даже предоставить значение по умолчанию (используя = someValue после объявления параметра), которое будет использоваться если при вызове не было предоставлено иного значения этого параметра:
1 2 3 4 5 6
function foo(bar: number, bas: string = 'hello') console.log(bar, bas); > foo(123); // 123, hello foo(123, 'world'); // 123, world
Перегрузки¶
TypeScript позволяет объявлять перегрузки функций. Это полезно для документации + проверки типов. Рассмотрим следующий код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
function padding( a: number, b?: number, c?: number, d?: any ) if ( b === undefined && c === undefined && d === undefined ) b = c = d = a; > else if (c === undefined && d === undefined) c = a; d = b; > return top: a, right: b, bottom: c, left: d, >; >
Если вы внимательно посмотрите на код, вы поймете значения a , b , c , d меняются в зависимости от количества переданных параметров. Также функция ожидает только 1 , 2 либо 4 параметра. Эти ограничения могут быть обеспечены и задокументированы с использованием перегрузки функций. По сути через условие вы просто объявляете параметры функции несколько раз. Последние объявленные параметры — это те, которые действительно используются внутри тела функции, но недоступные извне.
Это показано ниже:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
// Перегрузки function padding(all: number); function padding( topAndBottom: number, leftAndRight: number ); function padding( top: number, right: number, bottom: number, left: number ); // Практическая реализация содержащая все случаи, которые должно обрабатывать // тело функции function padding( a: number, b?: number, c?: number, d?: number ) if ( b === undefined && c === undefined && d === undefined ) b = c = d = a; > else if (c === undefined && d === undefined) c = a; d = b; > return top: a, right: b, bottom: c, left: d, >; >
Здесь первые три случая использования параметров доступны как допустимые вызовы padding :
1 2 3 4 5
padding(1); // Okay: все padding(1, 1); // Okay: topAndBottom, leftAndRight padding(1, 1, 1, 1); // Okay: top, right, bottom, left padding(1, 1, 1); // Ошибка: Не входит в число доступных перегрузок
Конечно, важно, чтобы последнее объявление (истинное объявление, видимое внутри функции) было совместимо со всеми перегрузками. Потому что это важный смысл вызовов функций, которые тело функции должно учитывать.
Перегрузка функций в TypeScript не приводит к увеличению нагрузки во время выполнения. Она просто позволяет документировать как функция будет вызываться, а компилятор контролирует оставшуюся часть кода.
Как в TS получить тип, возвращаемого функцией результата?
Функция runAgents принимает дикт с классом, у которого есть метод parse()
и возвращяет дикт с результатами работы функции.
Как объявить тип результата (IAgentsResult) функции runAgents что бы TS сам подставлял правильные типы в зависимости от входного типа?
export interface IAgentList <[key: string]: IAgentBase> export interface IAgents extends IAgentList < items?: IItemsParser; page?: IPageParser; parser?: IWebParser; >export interface IAgentBase < parse(): Promise; > export interface IItemsParser extends IAgentBase < >export interface IPageParser extends IAgentBase < >export interface IWebParser extends IAgentBase < >export interface IAgentsResult < items?: IItem[]; page?: IDataSet[]; parser?: any; >// в реальности все иначе, написал для понимания желаемого результата async function runAgents(agents: IAgentList): Promise < const result: IAgentsResult= <>; Object.keys(agents).forEach( async key => result[key] = await agents[key].parse() ); return result; > const agents : IAgents = const result = runAgents(agents)
- Вопрос задан более трёх лет назад
- 632 просмотра