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.
Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.11.15.1019
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Как вызвать функцию в 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, за которым следуют сигнатура функции и тело функции. В приведенном ниже примере мы создали функцию с именем userDefinedFunction, где мы печатали сообщение в журнал.
function userDefinedFunction() < console.log("Hello World!"); >userDefinedFunction();
Результат: Hello World!
Передача параметров и возвращаемого значения: Мы можем добавить параметры и ожидать возвращаемое значение как часть определения функции. В приведенном ниже примере мы передали два параметра i и j типа данных номер, с возвращаемым значением в качестве числа.
function add(i: number, j: number): number < return i + j; >function mul(i: number, j: number): number < return i * j; >let result = add(2,3); console.log("add(2,3) is " + result); result = mul(2,3); console.log("mul(2,3) is " + result);
Результат:
add(2,3) is 5
mul(2,3) is 6
Функции со значениями по умолчанию в параметрах: Мы можем передать значение по умолчанию для параметра, переданного функции. В приведенном ниже примере мы добавили значение по умолчанию 10 к параметру j. Теперь мы можем вызвать функцию «add» без второго параметра, и она автоматически примет значение 10.
function add(i: number, j=10): number < return i + j; >let result = add(2,3); console.log("add(2,3) is " + result); result = add(2); console.log("add(2) is " + result);
Результат:
add(2,3) is 5
add(2) is 12
Функциональные выражения: Мы можем создавать функции как выражения и присваивать их переменной. В приведенном ниже примере мы создали mathFunction как функцию, которая добавляет два числа. Затем мы переопределили функцию для умножения двух чисел.
let mathFunction = function(i: number, j: number): number < return i + j; >; let result = mathFunction(2, 3); console.log("mathFunction(2,3) is " + result); mathFunction = function(i: number, j: number): number < return i * j; >; result = mathFunction(2, 3); console.log("mathFunction(2,3) is " + result);
Результат:
mathFunction(2,3) is 5
mathFunction(2,3) is 6
Стрелка Функции: Мы можем создавать функции, содержащие простые выражения, используя функции Arrow. В приведенном ниже примере мы создали две функции со стрелками: одну для добавления двух чисел и другую для умножения двух чисел и присвоили ее переменной mathFunction.
let mathFunction = (i: number,j: number) => i + j; console.log( mathFunction(2,3) ); mathFunction = (i,j) => i * j; console.log( mathFunction(2,3) );
Результат:
5
6
Встроенные функции: TypeScript предоставляет несколько встроенных функций. Давайте рассмотрим три популярных: оповещение, подсказка и подтверждение. Функция оповещения может использоваться для вывода на экран сообщения оповещения. Функция подсказки может быть использована для получения некоторых отзывов или данных от пользователя. Функция подтверждения может быть использована для получения истинного ложного ответа от пользователя, скажем, перед удалением файла.
alert(«Howdy partner. «); let feedback = prompt(«Can you gimme some feedback?», «Worst website»); console.log(«Feedback output»> Результат:
Feedback = Worst website
let response = confirm(«Shall I set the world on fire?»); console.log(«Set World on Fire output»> Результат:
Set World on Fire = true
Share this page:
Report Error in Content
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.
Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.11.15.1019
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Как вызвать функцию в 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
Функции TypeScript
Функции — это набор операторов, которые обрабатывают ввод и возвращают вывод. В TypeScript функции определяются с помощью ключевого слова function, за которым следуют сигнатура функции и тело функции. В приведенном ниже примере мы создали функцию с именем userDefinedFunction, где мы печатали сообщение в журнал.
function userDefinedFunction() < console.log("Hello World!"); >userDefinedFunction();
Результат: Hello World!
Передача параметров и возвращаемого значения: Мы можем добавить параметры и ожидать возвращаемое значение как часть определения функции. В приведенном ниже примере мы передали два параметра i и j типа данных номер, с возвращаемым значением в качестве числа.
function add(i: number, j: number): number < return i + j; >function mul(i: number, j: number): number < return i * j; >let result = add(2,3); console.log("add(2,3) is " + result); result = mul(2,3); console.log("mul(2,3) is " + result);
Результат:
add(2,3) is 5
mul(2,3) is 6
Функции со значениями по умолчанию в параметрах: Мы можем передать значение по умолчанию для параметра, переданного функции. В приведенном ниже примере мы добавили значение по умолчанию 10 к параметру j. Теперь мы можем вызвать функцию «add» без второго параметра, и она автоматически примет значение 10.
function add(i: number, j=10): number < return i + j; >let result = add(2,3); console.log("add(2,3) is " + result); result = add(2); console.log("add(2) is " + result);
Результат:
add(2,3) is 5
add(2) is 12
Функциональные выражения: Мы можем создавать функции как выражения и присваивать их переменной. В приведенном ниже примере мы создали mathFunction как функцию, которая добавляет два числа. Затем мы переопределили функцию для умножения двух чисел.
let mathFunction = function(i: number, j: number): number < return i + j; >; let result = mathFunction(2, 3); console.log("mathFunction(2,3) is " + result); mathFunction = function(i: number, j: number): number < return i * j; >; result = mathFunction(2, 3); console.log("mathFunction(2,3) is " + result);
Результат:
mathFunction(2,3) is 5
mathFunction(2,3) is 6
Стрелка Функции: Мы можем создавать функции, содержащие простые выражения, используя функции Arrow. В приведенном ниже примере мы создали две функции со стрелками: одну для добавления двух чисел и другую для умножения двух чисел и присвоили ее переменной mathFunction.
let mathFunction = (i: number,j: number) => i + j; console.log( mathFunction(2,3) ); mathFunction = (i,j) => i * j; console.log( mathFunction(2,3) );
Результат:
5
6
Встроенные функции: TypeScript предоставляет несколько встроенных функций. Давайте рассмотрим три популярных: оповещение, подсказка и подтверждение. Функция оповещения может использоваться для вывода на экран сообщения оповещения. Функция подсказки может быть использована для получения некоторых отзывов или данных от пользователя. Функция подтверждения может быть использована для получения истинного ложного ответа от пользователя, скажем, перед удалением файла.
alert(«Howdy partner. «); let feedback = prompt(«Can you gimme some feedback?», «Worst website»); console.log(«Feedback output»> Результат:
Feedback = Worst website
let response = confirm(«Shall I set the world on fire?»); console.log(«Set World on Fire output»> Результат:
Set World on Fire = true
Share this page:
Report Error in Content
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 .
