如何在具有角度注入参数的打字稿中创建新对象

Posted

技术标签:

【中文标题】如何在具有角度注入参数的打字稿中创建新对象【英文标题】:How to create new object in typescript having angular-injected parameters 【发布时间】:2016-07-19 22:44:57 【问题描述】:

我有一个 typescript 类,在构造函数中我有一个普通的和一个角度注入的参数:

export class MyClass 
    private translation:string;

    public static $inject = ['$filter'];
    constructor(name:string, $filter: ng.IFilterService) 
        this.translation = filter('translate')('code').toString();
    

如果我现在想创建一个对象,我该怎么做?

new MyClass('myname'); //won't compile because there are too few parameters
new MyClass('myname', filter); //makes no sense since I want to inject it

即使我写了$filter?,它也不起作用,因为它无法识别范围并且它是未定义的。

那么,我怎样才能让它工作呢?

我的方法

假设我在另一个类中,我想在其中创建 MyClass 的对象。下面的代码可以工作,但我不喜欢在这个类中也注入 $filter 的想法,因为它不需要它。

export class ClassUsingTheOtherClass 
    private filter:ng.IFilterService;

    public static $inject = ['$filter'];
    constructor($filter: ng.IFilterService) 
        this.filter = $filter;
    

    doThings() 
        var clazz = new MyClass('myName', this.filter);
    

我宁愿调用像这样的var clazz = new MyClass('myName'); 并让$filter 作为依赖项自动注入到MyClass 中。这可能吗?

【问题讨论】:

你什么时候会打电话给new MyClass('myname');?似乎永远不会调用它,因为您需要一个 filter 实例,否则该类最终将遇到未定义的错误。 myname 参数的用途是什么?这怎么可能被注射?该定义不适用于 Angular。 我重写了这个问题。看一看。 myname 只是要使用 angular-translate 过滤器翻译的字符串。而且我不希望它被注入,因为我想在需要翻译时传递它。 【参考方案1】:

我认为您缺少有关 DI(注入)的内容。关键是不要手动创建任何依赖项。相反,总是解决它们,并且使用 Angular,这是在构造函数中自动完成的。唯一的例外应该是具有 0 角度依赖性并且限制为没有像纯实体/数据类这样的行为的类。

Typescript 还为您提供定义接口(合同)的能力。您应该创建它们并将它们用作参考点,而不是直接使用您的类类型。这将允许您更改行为甚至定义(提供松散耦合)。这也使单元测试更容易。

您的示例可以这样重写:

export interface IMyService
   doThing:()=>void;


// should be registered with angular with service name 'ngMyService'
export class MyClass implements IMyService 
    private translation:string;

    public static $inject = ['$filter'];
    constructor($filter: ng.IFilterService) 
        this.translation = $filter('translate')('code').toString();
    

    doThing() : void 
        // something
    


export class ClassUsingTheOtherClass 

    public static $inject = ['ngMyService'];
    constructor(private myService: IMyService) 
    

    doThings() 
        this.myService.doThing();
    

现在使用名称ngMyService 注册MyClass 并使用名称注册ClassUsingTheOtherClass。您在哪里注册它们取决于它们的用途(控制器、服务、工厂、过滤器等)。

当 Angular 创建 ClassUsingTheOtherClass 的实例时,它会自动将 MyClass 注入到构造函数中。 MyClass 会自动将$filter 注入到构造函数中。

最后我发现MyClass 中的字符串name 参数没有任何意义,所以我删除了它。您将永远无法注入它,因为您无法使用要注入的角度注册字符串。您可以在类型本身中硬编码名称,也可以提供MyClass 的用户可以设置的name 属性/字段(将字段添加到接口IMyService),但这打破了高内聚规则我的意见。

【讨论】:

我喜欢它。问题并不是对 DI 的普遍误解,而是我并没有真正按照我应该的方式使用角度。我有点试图避免以角度注册每一件事,但现在我看到这是要走的路。无论如何,我认为这是可以在 Typescript 中改进的东西 好答案。尽可能关注原因和方法 @iberbeu -(更正,我的意思是写Good not God) - 很好!当我第一次开始使用 Angular 和 Typescript(我同时使用它们)时,我也花了一点时间。一旦你掌握了它(通过接口定义依赖关系和使用角度注册等),它就变成了你几乎不必再考虑的事情(第二自然)。【参考方案2】:
export class MyClass 

    public static $inject = ['$scope'];
    constructor(name:string, $scope?: ng.IScope) 
        //do things...                
    

通过修改你的类,使$scope 后面有一个问号,你告诉编译器$scope 是一个可选参数。

现在您可以简单地运行new MyClass('myname');

【讨论】:

你试过了吗?它确实像我在问题中所说的那样编译,但范围将是未定义的 我好像看错了你的问题,我以为是编译的问题。我试图理解你的问题,但我真的不知道你为什么要在泛型类中注入一个范围。如果它需要 $scope,您可能应该为每个类提供他自己的 $scope,它继承自生成新实例的类的 $scope。 new MyClass('myname', scope.$new(false)); 写范围是个坏主意。我真正需要的是 $filter 来翻译一个东西。我重写了我的问题。还有另一种方法可以做到这一点吗?我在这里误会了吗?

以上是关于如何在具有角度注入参数的打字稿中创建新对象的主要内容,如果未能解决你的问题,请参考以下文章

在打字稿中带有参数类型的角度 ui-state

在角度/打字稿中将类创建为可迭代

如何在 Loopback 4(打字稿)中调用具有依赖注入的类的方法?

在打字稿中的类中创建具有未知参数的方法

如何在打字稿的泛型类中创建类型为“T”的新对象?

如何通过两个对象打字稿角度6进行比较