Есть ли разница в TypeScript между функцией и лямбдой? Что может произойти если заменить одну на другую? Давайте посмотрим.
Различие функции и лямбды в TypeScript
Много ли различий между следующими строками (особенно глазами разработчика на C#):
$.ajax({ … }).done(function (response: any) { … });
$.ajax({ … }).done((response: any) => { … });
На первый взгляд, разницы никакой и можно смело использовать любой из вариантов. Например, даже так:
$.ajax({ … })
.done((response: any) => { … })
.fail(function (response: any) { … })
.always(function () { … });
Однако, с точки зрения TypeScript, разница между 2 и 3 строкой достаточно большая.
Лямбда воспринимается как член класса. При этом, внутри нее this указывает на экземпляр класса и его тип контролируется при компиляции. Если посмотреть JavaScript код, то можно увидеть замену this на _this.
Внутри функции указатель this получает тип any и указывает на вызывающий объект. Соответственно, контроль вызовов её функций и полей осуществляется только во время исполнения скрипта. В JavaScript коде this остается без изменений.
Таким образом использование лямбды более предпочтительно из-за типизации this и контроля типов и вызовов уже на этапе компиляции.
Поставляем правильный this в функцию
Иногда поведение this в функции можно компенсировать явно указав контекст, где это возможно:
$.ajax({ …, context: this })
.done(function (response: any) { … })
.fail(function (response: any) { … })
.always(function () { … });
Сложности замены функции на лямбду
Другой интересный момент, заключается в замене функции на лямбду. Код, который успешно работал, может просто перестать компилироваться. Это произойдет из-за обращений к реально существующим, но не объявленным в файлах TypeScript переменным и функциям.
Например, в AngularJS есть переменная $scope, которая содержит $parent - указатель на своего родителя. Их базовые типы объявлены в TypeScript. Но $parent может содержать дополнительные переменные.
В случае использования функции возможен вот такой вызов: this.$scope.$parent.someValue. Поскольку this имеет тип any, то $scope, $parent и someValue также будут any. Ошибки компиляции не будет и сам код будет работать, если parent действительно содержит такую переменную.
Разумеется, при замене на лямбду будет ошибка из-за неизвестной someValue.
Использование такого подхода в функциях делает код менее на надежным. Переименование, удаление или изменения типа someValue будут заметны только в момент выполнения. Поэтому использование лямбд предпочтительнее и в этом случае, даже при необходимости модификации кода.
Intellisense
В завершении стоит отметить интересный факт. Внутри функций Visual Studio Intellisense предлагает достаточно корректный список постановок для this. Если не присматриваться, то можно даже не заметить разницы с лямбдой.