背景
在我正在开发的项目中,我们已经从使用带有JavaScript的AngularJS(1.6.2)切换到TypeScript 2.1.5。
我们有一个应用于$exceptionHandler
服务的装饰器,它导致JavaScript异常调用通用API,向开发团队发送电子邮件;通过这种方式,我们可以很容易地看到最终用户在野外遇到的前端错误。
问题:
我最近将这个装饰器从JavaScript转换为TypeScript。当我尝试运行应用程序时,我遇到了什么都没有的白屏。经过大量调试后,我发现问题是因为AngularJS希望$provide.decorator
传递一个函数以及依赖项列表。但是,正在观察一个对象,从而迫使Angular进行故障安全。
我通过在angular.js
内部设置断点来诊断问题;由于抛出的,未处理的JavaScript异常,它特别会在第4809行(函数createInternalInjector(cache, factory)
内部)失败,但实际负责失败的部分是函数invoke(fn, self, locals, serviceName)
内的第4854行。它失败的原因是因为传递的依赖关系是['$delegate', '$injector',]
;该集合缺少该功能。
最后,我考虑做的一件事就是在类代码中定义一个JavaScript函数。由于两个原因,这在我的案例中不起作用。首先,在我们的ts.config
中,我们将noImplicitAny
设置为true;函数隐含于any
类型。此外,TypeScript本身似乎不会将function
识别为关键字,而是尝试将其编译为类ExceptionHandler
上的符号而无法将其编译。
TypeScript异常处理程序:
export class ExceptionHandler {
public constructor(
$provide: ng.auto.IProviderService
) {
$provide.decorator('$exceptionHandler`, [
'$delegate',
'$injector',
this.dispatchErrorEmail
]);
}
public dispatchErrorEmail(
$delegate: ng.IExceptionHandlerService,
$injector: ng.auto.IInjectorService
): (exception: any, cause: any) => void {
return (exception: any, cause: any) => {
// First, execute the default implementation.
$delegate(exception, cause);
// Get our Web Data Service, an $http wrapper, injected...
let webDataSvc: WebDataSvc = $injector.get<WebDataSvc>('webDataSvc');
// Tell the server to dispatch an email to the dev team.
let args: Object = {
'exception': exception
};
webDataSvc.get('/api/common/errorNotification', args);
};
}
}
angular.module('app').config(['$provide', ExceptionHandler]);
原创JS:
(function () {
'use strict';
angular.module('app').config(['$provide', decorateExceptionHandler]);
function decorateExceptionHandler($provide) {
$provide.decorator('$exceptionHandler', ['$delegate', '$injector', dispatchErrorEmail]);
}
function dispatchErrorEmail($delegate, $injector) {
return function (exception, cause) {
// Execute default implementation.
$delegate(exception, cause);
var webDataSvc = $injector.get('webDataSvc');
var args = {
'exception': exception,
};
webDataSvc.get('/api/common/ErrorNotification', args);
};
}
})();
问题:
1.我可以用什么方式重写TypeScript异常处理程序,以便AngularJS正确选取?
2.如果我不能,这是一个需要升级的AngularJS错误吗?我知道事实上我不是唯一一个使用TypeScript的AngularJS的人;由于语言选择而无法装饰服务似乎是一个非常重要的问题。
答案 0 :(得分:2)
将所有内容转换为类不是TS的目的,这里的类没有用处。 JS代码应该使用类型进行扩充,并且可能使用$inject
注释进行增强。
angular.module('app').config(decorateExceptionHandler);
decorateExceptionHandler.$inject = ['$provide'];
export function decorateExceptionHandler($provide: ng.auto.IProviderService) {
$provide.decorator('$exceptionHandler', dispatchErrorEmail);
}
dispatchErrorEmail.$inject = ['$delegate', '$injector'];
export function dispatchErrorEmail(
$delegate: ng.IExceptionHandlerService,
$injector: ng.auto.IInjectorService
): (exception: any, cause: any) => void { ... }
config
需要常规函数,而不是构造函数。并且原始TS代码失败的原因是ExceptionHandler
未使用new
调用,因此this
不是对象,this.dispatchErrorEmail
不是函数。< / p>
答案 1 :(得分:1)
以下是使用TypeScript namespaces执行此操作的另一种方法。对我来说感觉有点干净,保持异常扩展功能是孤立的,并且在概念上来自C#之类的很好。
exception.module.ts
import * as angular from 'angular';
import { LoggerModule } from '../logging/logger.module';
import { ExceptionExtension } from './exception.handler';
export const ExceptionModule = angular.module('app.common.exception', [LoggerModule])
.config(ExceptionExtension.Configure)
.name;
exception.handler.ts
import { ILoggerService } from '../logging/logger.service';
export namespace ExceptionExtension {
export const ExtendExceptionHandler = ($delegate: ng.IExceptionHandlerService, logger: ILoggerService) => {
return function (exception: Error, cause?: string): void {
$delegate(exception, cause);
logger.error(exception.message, "Uncaught Exception", cause ? cause : "");
}
};
ExtendExceptionHandler.$inject = ['$delegate', 'ILoggerService'];
export const Configure = ($provide: ng.auto.IProvideService) => {
$provide.decorator('$exceptionHandler', ExtendExceptionHandler);
};
Configure.$inject = ['$provide'];
}