Как вызвать функцию в javascript typescript
Перейти к содержимому

Как вызвать функцию в javascript typescript

  • автор:

Как вызвать функцию в javascript typescript

В 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

Function, Functional Types¶

Функция — это ключевая концепция JavaScript. Функции присваиваются в качестве значений переменным и передаются как аргументы при вызове других функций. Поэтому не удивительно, что TypeScript очень много внимания уделяет возможностям функционального типа, к которым, начиная с текущей главы, повествование периодически будет возвращаться.

Function Types — тип функция¶

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

 1 2 3 4 5 6 7 8 9 10
function f1(p1: number): string  return p1.toString(); > function f2(p1: string): number  return p1.length; > let v1: Function = f1; let v2: Function = f2; 

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

Поведение типа Function идентично одноимённому типу из JavaScript.

Functional Types — функциональный тип¶

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

Функциональный тип обозначается с помощью пары круглых скобок () , после которых располагается стрелка, а после неё обязательно указывается тип возвращаемого значения () => type . При наличии у функционального выражения параметров, их декларация заключается между круглых скобок (p1: type, p2: type) => type .

type FunctionalType = (p1: type, p2: type) => type; 

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

1 2 3 4
type SumFunction = (a: number, b: number) => number; const sum: SumFunction = (a: number, b: number): number => a + b; 

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

this в сигнатуре функции¶

Ни для кого не будет секретом, что в JavaScript при вызове функций можно указать их контекст. В львиной доле случаев, возможность изменять контекст вызова функции является нежелательным поведением JavaScript, но только не в случае реализации конструкции, называемой функциональная примесь (functional mixins).

Функциональная примесь — это функция, в теле которой происходит обращение к членам, объявленным в объекте, к которому она “примешивается”. Проблем не возникнет, если подобный механизм реализуется в динамически типизированном языке, каким является JavaScript.

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// .js class Animal  constructor()  this.type = 'animal'; > > function getType()  return this.type; > let animal = new Animal(); animal[getType.name] = getType; console.log(animal.getType()); // animal 

Но в статически типизированном языке такое поведение должно быть расценено как ошибочное, поскольку у функции нет присущего объектам признака this . Несмотря на это в JavaScript, а значит и в TypeScript, контекст самой программы (или, по другому, глобальный объект) является объектом. Это в свою очередь означает, что не существует места, в котором бы ключевое слово this привело к возникновению ошибки (для запрещения this в нежелательных местах нужно активировать опцию компилятора —noImplicitThis ). Но при этом за невозможностью предугадать поведение разработчика, в TypeScript ссылка this вне конкретного объекта ссылается на тип any , что лишает ide автодополнения. Для таких и не только случаев была реализована возможность декларировать тип this непосредственно в функциях.

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

1 2 3 4 5
interface IT1  p1: string; > function f1(this: IT1): void <> 

Несмотря на то, что this декларируется в параметрах функции, таковыми оно не считается. Поведение функции с декларацией this аналогично поведению функции без декларации this . Единственное, на что стоит обратить внимание, что в случае указания принадлежности к типу, отличному от void , не получится вызвать функцию вне указанного контекста.

 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
interface IT1  p1: string; > function f1(this: void): void <> function f2(this: IT1): void <> function f3(): void <> f1(); // Ok f2(); // Error f3(); // Ok let v1 =  // v1: void;> f2: f2, >; v1.f2(); // Error let v2 =  // v2: void;> p1: '', f2: f2, >; v2.f2(); // Ok 

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

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
class Point  constructor(public x: number = 0, public y: number = 0) <> > class Animal  private readonly position: Point = new Point(); public move( clientX, clientY >: MouseEvent): void  this.position.x = clientX; this.position.y = clientY; > > let animal = new Animal(); // ошибка во время выполнения document.addEventListener('mousemove', animal.move); 

Для этих случаев TypeScript предлагает ограничить ссылку на контекст с помощью конкретизации типа ссылки this .

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

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
type IContextHandler = ( this: void, event: MouseEvent ) => void; class Controller  public addEventListener( type: string, handler: IContextHandler ): void <> > let animal = new Animal(); let controller = new Controller(); // ошибка во время выполнения controller.addEventListener('mousemove', animal.move); 

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

 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
class Point  constructor(public x: number = 0, public y: number = 0) <> > class Animal  private readonly position: Point = new Point(); public move( this: Animal,  clientX, clientY >: MouseEvent ): void  // this.position.x = clientX; this.position.y = clientY; > > type IContextHandler = ( this: void, event: MouseEvent ) => void; class Controller  public addEventListener( type: string, handler: IContextHandler ): void <> > let animal = new Animal(); let controller = new Controller(); controller.addEventListener('mousemove', animal.move); // ошибка во время компиляции controller.addEventListener('mousemove', (event) => animal.move(event) ); // Ok 

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

TypeScript: Функции как параметры

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

Как типизировать функции, которые передаются как параметры

Самый простой способ типизировать функции как параметры — использовать тип Function . Он описывает функцию JavaScript со всеми ее особенностями, включая свойства bind , call и apply .

Опишем входной параметр callback функции process :

function process(callback: Function) < const value = callback(); // . >

Function отключает проверку типов для вызываемой функции. В итоге количество и тип входных аргументов не проверяются, а результатом работы такой функции будет any . Это может привести к логическим ошибкам и неожиданному поведению:

process(Math.round); // ? 

Данный пример сработает, хотя поведение вряд ли будет ожидаемым, так как Math.round вызовется без аргументов и вернет NaN . Поэтому мы рекомендуем избегать использования Function .

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

function process(callback: () => string) < // value имеет тип string const value = callback(); // . >process(Math.round); // Argument of type '(x: number) => number' is not // assignable to parameter of type '() => string'. 

Определение стрелочной функции похоже на настоящую, но тут важно не перепутать. Здесь мы видим именно описание типа, а не определение функции.

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

function process(callback: () => number) function process(callback: () => string[]) function process(callback: () => < firstName: string; >) 

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

function process(callback: (n: number) => string) < const value = callback(10); // . >

Здесь мы определили тип callback функцией с параметром n с типом number и возвращаемое значение string .

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

type myFunction = (n: number) => string; function process(callback: myFunction) < const value = callback(10); // . >

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

Задание

Реализуйте функцию filter() , которая принимает на вход массив чисел и предикат. Последний будет использоваться для проверки каждого числа на соответствие требованиям:

const numbers = [1, -5, 2, 3, 4, 133]; filter(numbers, (n) => n > 3); // [4, 133] filter(numbers, (n) => n % 2 == 0); // [2, 4] 
  1. Массив чисел
  2. Анонимная функция, которая принимает на вход число и возвращает логическое значение

Упражнение не проходит проверку — что делать? ��

Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:

  • Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.

В моей среде код работает, а здесь нет ��

Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.

Мой код отличается от решения учителя ��

Это нормально ��, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.

В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.

Прочитал урок — ничего не понятно ��

Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.

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

Полезное

TypeScrpt | Как мне использовать в .js функции .ts?

В файле .ts у меня есть функция, которая принимает два параметра, оба типа number . Она возвращает сумму этих двух параметров. А в .js файле я запрашиваю .ts файл. Дело в том, что в JS неудобно писать перед каждой функцией

/** *@params a *@params b */ 

Можно ли мне через JavaScript файл вызвать мою функцию на TypeScript ? Мой код на TS:

export const Foo = (a: number, b: number) =>

Отслеживать
задан 27 фев 2021 в 9:18
439 2 2 серебряных знака 12 12 бронзовых знаков
.d.ts — TS файл деклараций для JS. Например в песочнице справа кнопка «JS .D.TS Errors Logs Plugins»
1 мар 2021 в 3:06
1 мар 2021 в 3:07
Возможно, стоит посмотреть на флаг allowjs в файле настроек тс
2 мар 2021 в 4:39

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Для того чтобы это сделать — Вам придется компилировать весь Ваш проект с помощью typescript.

Сделал небольшой пример, код в песочницу запихнуть не удалось — поэтому вот ссылка на git:

Привел два направления — вызов из js ts и широко известная — вызов из ts js

Собственно основной рецепт — это параметр в tsconfig.json «allowJs»: true

Отслеживать
ответ дан 2 янв 2022 в 7:27
Gayrat Vlasov Gayrat Vlasov
591 6 6 серебряных знаков 15 15 бронзовых знаков

  • javascript
  • typescript
    Важное на Мете
Похожие

Подписаться на ленту

Лента вопроса

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.30.4069

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *