简体   繁体   English

无法使用TypeScript修饰AngularJS的ExceptionHandler,因为函数不被识别

[英]Cannot decorate AngularJS' ExceptionHandler using TypeScript, as a function isn't recognized as such

Background: 背景:
On a project I am working on, we've switched from using AngularJS (1.6.2) with JavaScript, to TypeScript 2.1.5. 在我正在开发的项目中,我们已经从使用带有JavaScript的AngularJS(1.6.2)切换到TypeScript 2.1.5。

We have a decorator applied to the $exceptionHandler service that causes JavaScript exceptions to make a call to a common API that send the development team an e-mail; 我们有一个应用于$exceptionHandler服务的装饰器,它导致JavaScript异常调用向开发团队发送电子邮件的公共API; in this way, we can easily see what front-end errors our end-users are encountering in the wild. 通过这种方式,我们可以很容易地看到最终用户在野外遇到的前端错误。

Problem: 问题:
I recently converted this decorator from JavaScript, to TypeScript. 我最近将这个装饰器从JavaScript转换为TypeScript。 When I try to run the application, I encounter a whitescreen of nothing. 当我尝试运行应用程序时,我遇到了什么都没有的白屏。 After much debugging I discovered that the issue is because AngularJS expects the $provide.decorator to pass a function along with a list of dependencies. 经过大量调试后,我发现问题是因为AngularJS希望$provide.decorator传递一个函数以及一个依赖列表。 However, an object is instead being observed, and thus forcing Angular to fail-safe. 但是,正在观察一个对象,从而迫使Angular进行故障安全。

I diagnosed the problem by setting breakpoints inside of angular.js itself; 我通过在angular.js设置断点来诊断问题; it specifically will fail on line 4809 (inside of function createInternalInjector(cache, factory) ) due to a thrown, unhandled JavaScript exception, but the part that's actually responsible for the failure is line 4854, inside of function invoke(fn, self, locals, serviceName) . 由于抛出的,未处理的JavaScript异常,它特别会在第4809行(在函数createInternalInjector(cache, factory) )失败,但是实际负责失败的部分是4854行,在函数invoke(fn, self, locals, serviceName)内部invoke(fn, self, locals, serviceName) The reason it fails, is because the dependencies passed come across as ['$delegate', '$injector',] ; 它失败的原因是因为传递的依赖关系是['$delegate', '$injector',] ; the function is missing from this set. 该集合中缺少该功能。

Lastly, one thing I considered doing was simply defining a JavaScript function in the class code. 最后,我考虑过的一件事就是在类代码中定义一个JavaScript函数。 This does not work in my case for two reasons. 由于两个原因,这在我的案例中不起作用。 First, in our ts.config , we have noImplicitAny set to true; 首先,在我们的ts.config ,我们将noImplicitAny设置为true; functions are implicitly of the any type. 函数隐含在any类型中。 Additionally, TypeScript itself appears not to recognize function as a keyword, and instead tries and fails to compile it as a symbol on class ExceptionHandler . 此外,TypeScript本身似乎不会将function识别为关键字,而是尝试将其编译为类ExceptionHandler上的符号。

TypeScript Exception Handler: 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]);

Original JS: 原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);
        };
    }
})();

Questions: 问题:
1. In what way can I rewrite the TypeScript Exception Handler to be properly picked up by AngularJS? 1.我可以用什么方式重写TypeScript异常处理程序,以便AngularJS正确选择?
2. If I can't, is this an AngularJS bug that needs to be escalated? 2.如果我不能,这是一个需要升级的AngularJS错误吗? I know for a fact I'm not the only person using AngularJS with TypeScript; 我知道事实上我不是唯一一个使用TypeScript的AngularJS的人; being unable to decorate a service due to language choice seems like a pretty major problem. 由于语言选择而无法装饰服务似乎是一个非常重要的问题。

Converting everything to classes isn't the purpose of TS, there's no use for classes here. 将所有内容转换为类不是TS的目的,这里的类没有用处。 JS code is supposed to be augmented with types and probably be enhanced with $inject annotation. 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 expects a regular function, not a constructor. config需要常规函数,而不是构造函数。 And the reason why the original TS code fails is that ExceptionHandler isn't called with new , thus this is not an object, and this.dispatchErrorEmail is not a function. 原始TS代码失败的原因是没有使用new调用ExceptionHandler ,因此this不是对象,而this.dispatchErrorEmail不是函数。

Here's another way to do it using TypeScript namespaces . 这是使用TypeScript命名空间执行此操作的另一种方法。 It feels a little cleaner to me, keeping the exception extension functions isolated, and is a nice conceptually coming from something like C#. 对我来说感觉有点干净,保持异常扩展功能是孤立的,并且在概念上来自C#之类的东西。

exception.module.ts 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 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'];
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM