例外:无法解析所有参数


431

我已经在Angular 2中构建了一个基本应用程序,但是遇到一个奇怪的问题,即我无法将服务注入我的组件之一。但是,它可以很好地注入我创建的其他三个组件中的任何一个。

对于初学者,这是服务:

import { Injectable } from '@angular/core';

@Injectable()
export class MobileService {
  screenWidth: number;
  screenHeight: number;

  constructor() {
    this.screenWidth = window.outerWidth;
    this.screenHeight = window.outerHeight;

    window.addEventListener("resize", this.onWindowResize.bind(this) )
  }

  onWindowResize(ev: Event) {
    var win = (ev.currentTarget as Window);
    this.screenWidth = win.outerWidth;
    this.screenHeight = win.outerHeight;
  }

}

以及它拒绝使用的组件:

import { Component, } from '@angular/core';
import { NgClass } from '@angular/common';
import { ROUTER_DIRECTIVES } from '@angular/router';

import {MobileService} from '../';

@Component({
  moduleId: module.id,
  selector: 'pm-header',
  templateUrl: 'header.component.html',
  styleUrls: ['header.component.css'],
  directives: [ROUTER_DIRECTIVES, NgClass],
})
export class HeaderComponent {
  mobileNav: boolean = false;

  constructor(public ms: MobileService) {
    console.log(ms);
  }

}

我在浏览器控制台中遇到的错误是这样的:

例外:无法解析HeaderComponent的所有参数:(?)。

我在引导功能中具有该服务,因此它具有提供程序。而且我似乎可以将其注入到其他任何组件的构造函数中,而不会出现问题。


14
也许是进口?是'../'index.ts(桶)?您可以尝试从直接声明的文件中导入它吗?
君特Zöchbauer

好像已经解决了!奇怪的是,当我测试过该服务的其他组件都无法使用时,它无法在桶中使用。如果您想将其发布为答案而不是评论,我会接受。
基思·奥托

11
通常是循环依赖。
加里

我也有循环依赖的问题。值得注意的是,较新版本的Web Pack更能告诉您这一点
Enn

看起来像是循环依赖项,如果使用angular> = 4,则可以摆脱intex.ts(桶)并直接导入所有需要的内容。
拉姆加洛特(Rammgarot)

Answers:


457

从直接声明的文件而不是桶中导入它。

我不知道是什么导致问题的确切原因,但是我多次提到它(可能是某种循环依赖)。

还应该通过更改桶中出口的顺序来固定(不知道细节,但也有人提到)


16
例如,如果您有一项服务注入了另一个服务,而该服务中的第一个需要首先出现在桶中,则这是正确的。
Joao Garin

17
Angular2团队不建议使用桶,因为存在许多此类问题。很高兴听到我能帮助:)
君特Zöchbauer

13
不知道Angular 2团队不推荐使用枪管。如果是这样,他们应该在讨论其收益的词汇表中注意这一点。而且像angular2-webpack-starter这样的项目不应该使用它们。
2016年

3
它表明此问题已解决(不是中的问题2.0.2)。我发现桶仍然有用,特别是当我需要在不同模块之间导入多个模型和服务时。import { cleanValues, getState, FirebaseService, NotificationService, ... } from '../../shared/services';当它不起作用时,这是一种痛苦(;NgModule对单例服务没有帮助……
Sasxa

3
我通过更改桶(index.ts)文件中的出口顺序解决了这个问题。非常感谢
Spock

331

除了先前给出的答案之外,当您的可注射服务缺少实际的@Injectable()装饰器时,似乎也会引发此错误。因此,在调试循环依赖项和导入/导出的顺序之前,请简单检查一下服务是否已@Injectable()定义。

这适用于当前的Angular最新版本Angular 2.1.0。

我就此事开了一个问题


是的,此错误通常是因为您忘记添加@Injectable,例如,您可能只是Router从“ @ angular / router” 导入,而没有该injectable,则总是会发生此错误(只要您决定制作一行,代码使用该注射路由器。
埃里克Bishard

很棒的答案,我的问题是我在服务中添加了一个方法,并且在最后一个括号之后没有添加分号。我不知道为什么一定要这样,但是在组件类中却不是这样……现在,我很高兴继续前进!
egimaben

我有一个简单的模型给了我这个错误。我使用了在模型的构造函数中创建属性的快捷方式。属性的类型只有字符串和整数。然后突然开始出现此问题。添加@Injectable()解决了该问题。很奇怪,因为我的其他模型都没有添加Injectable。我必须补充一点,在添加此新模型之前,我已经升级了很多库。可能与它有关,但现在可以工作。谢谢。
Moutono

@Moutono正确。如果您的服务中有一个空的构造函数,则似乎不会触发@injectable()也不是必须的依赖注入。这本身就是另一个奇怪之处。虽然很好,但我还是会添加它,只是为了您何时应该决定注入某些东西。
JP十柏格

请记住,如果您的服务有一个基类,也需要用@Injectable()装饰
Sam Shiles

110

从Angular开始2.2.3,现在有一个forwardRef()实用程序功能,可让您注入尚未定义的提供程序。

未定义,是指依赖项注入映射不知道标识符。这是在循环依赖期间发生的情况。您可以在Angular中具有很难解开和看到的圆形依赖关系。

export class HeaderComponent {
  mobileNav: boolean = false;

  constructor(@Inject(forwardRef(() => MobileService)) public ms: MobileService) {
    console.log(ms);
  }

}

@Inject(forwardRef(() => MobileService))在原始问题的源代码中添加到构造函数的参数将解决此问题。

参考文献

Angular 2手册:ForwardRef

Angular 2中的前向引用


3
forwardRef()Alpha中是否已有;-)只有Mobile在同一文件中声明了更进一步的服务时才需要。如果类在不同的文件,也没有必要forwardRef()
君特Zöchbauer

4
GünterZöchbauer,我仍在努力找出我的代码的真正问题,但与此同时,它forwardRef()确实有助于摆脱该Can't resolve all parameters for ...信息。在寻找更好的解决方案时,至少该组件正在工作。(是的,失败的依赖项直接从其文件中导入)
Nik

4
@GünterZöchbauer我已经用参考文献更新了我的答案。我并不是想摆脱您的回答,但这实际上可以解决问题,并且人们需要了解它。如果您用谷歌搜索该问题,则没有可以使用的结果forwardRef。很难找到。昨天花了我整天的时间来解决这个问题。
Reactgular

奇怪的。我发布了至少十二个建议使用foreardRef自己的答案,但在NgModule介绍之后不再使用。我不担心失去销售代表。我只是很好奇为什么在几个月后这种现象不再出现之后,您为什么会遇到这个问题。几天后回家,我会仔细看一下。非常感谢您的反馈。
君特Zöchbauer

2
如果有人对导入也迷失了:从'@ angular / core'导入{Component,Inject,ForwardRefFn,forwardRef};
Natanael

69

错误#1:忘记装饰器:

//Uncaught Error: Can't resolve all parameters for MyFooService: (?).
export class MyFooService { ... }

错误#2:省略“ @”符号:

//Uncaught Error: Can't resolve all parameters for MyFooService: (?).
Injectable()
export class MyFooService { ... }

错误#3:省略“()”符号:

//Uncaught Error: Can't resolve all parameters for TypeDecorator: (?).
@Injectable
export class MyFooService { ... }

错误#4:小写的“ i”:

//Uncaught ReferenceError: injectable is not defined
@injectable
export class MyFooService { ... }

错误#5:您忘记了: 从'@ angular / core'导入{可注入};

//Uncaught ReferenceError: Injectable is not defined
@Injectable
export class MyFooService { ... }

正确:

@Injectable()
export class MyFooService { ... }


21

我也通过将服务A注入到服务B中而遇到了这种情况,反之亦然。

我认为这很快就失败是一件好事,因为无论如何应该避免。如果您希望服务更具模块化和可重用性,那么最好避免使用循环引用。这篇文章重点介绍了周围的陷阱。

因此,我有以下建议:

  • 如果您觉得类之间的交互过于频繁(我在谈论功能嫉妒),则可能需要考虑将2个服务合并为1个类
  • 如果上述方法对您不起作用,请考虑使用第三个服务(一个EventService),两个服务都可以注入该服务来交换消息。

1
这绝对是我发生的事情,这就是要走的路。如果您知道有多个服务需要更新,请使用EventService。它具有更高的可扩展性,因为您毫无疑问必须在基于这些事件扩展应用程序时利用这些事件。
themightybun

17

为了搜索者的利益;我得到这个错误。它只是一个缺少的@符号。

即,这会产生Can't resolve all parameters for MyHttpService错误。

Injectable()
export class MyHttpService{
}

添加缺少的@符号即可修复它。

@Injectable()
export class MyHttpService{
}

2
就我而言,我在@Injectable和服务类定义之间添加了额外的类和接口,因此不再将服务类标记为可注入。
Herc

如果您完全忘记使用其他可注入服务的服务类上的@Injectable()装饰器,则装饰不当的服务也会引发此错误。
I. Buchan's

10

就我而言,我需要添加import "core-js/es7/reflect";到我的应用程序中才能@Injectable工作。


9

另一个可能是没有emitDecoratorMetadata在tsconfig.json中将其设置为true

{
  "compilerOptions": {

     ...

    "emitDecoratorMetadata": true,

     ...

    }

}

8

如果您的服务A依赖于服务B静态属性/方法,并且服务B本身依赖于服务A的槽依赖注入,则会出现此错误。因此,这是一种循环依赖关系,尽管由于属性/方法是静态的,所以不是。可能是与AOT结合出现的错误。


当依赖于在同一文件中简单定义的函数时,我也会遇到它。将其拆分为一个单独的文件即可对其进行修复。

1
谢谢你提到它。我发现自己处境确切。我没有意识到直接访问静态类可能与DI有关。我有这个方案:A -> B他们两个都使用相同的静态类。带有forwardRef帮助的解决方案,但我将研究如何解决这个问题。我可能会尝试从此静态类中提供真正的服务(这也会导致更好的设计)。
Slava Fomin II

8

除了缺少的@Injectable()装饰器

@Injectable()抽象类中缺少装饰器,导致无法解析服务的所有参数:(?)装饰器MyService以及派生类中都需要装饰器BaseService

//abstract class
@Injectable()
abstract class BaseService { ... }

//MyService    
@Injectable()
export class MyService extends BaseService {
.....
}

7

就我而言,这是因为我没有为构造函数参数声明类型。

我有这样的事情:

constructor(private URL, private http: Http) { }

然后将其更改为以下代码即可解决我的问题。

constructor(private URL : string, private http: Http) {}

5

对我来说,只是()@Injectable中缺少。正确的是@Injectable()


或者以我为例,意外删除了@
TDP

4

从可注入的builder()方法中删除参数就我的情况解决了它。


这也是我的问题。我来发布它,但是发现您先发布了!+1
aesede '17

那么如何将参数发送到可重用服务?
3gwebtrain


2

对我来说,问题更令人烦恼,我在服务中使用服务,却忘记将其添加为appModule中的依赖项!希望这可以帮助某人节省几个小时来分解该应用程序,以便仅重新构建它


1
我只是缺少一个@Inject注释。我完全忽略了错误消息所说的内容。如果您不怀疑循环依赖,只需转到错误中提到的类,然后查看所有构造函数参数以及所有带注释的类成员,@Inject并确保对所有这些都正确进行了DI。有关DI的更多信息,请访问:angular.io/docs/ts/latest/guide/dependency-injection.html
Alexander Taylor

2

您必须在@Component装饰器或声明组件的模块中添加provider数组。在组件内部,您可以执行以下操作:

@Component({
  moduleId: module.id,
  selector: 'pm-header',
  templateUrl: 'header.component.html',
  styleUrls: ['header.component.css'],
  directives: [ROUTER_DIRECTIVES, NgClass],
  providers: [MobileService]
})

2

在我的情况下,将错误的参数传递给构造函数会产生此错误,有关此错误的基本思想是您在不知不觉中将一些错误的args传递给任何函数。

export class ProductComponent {
    productList: Array<Product>;

    constructor(productList:Product) { 
         // productList:Product this arg was causing error of unresolved parameters.
         this.productList = [];
    }
}

我通过删除该参数解决了这一问题。


2

对我来说,当我错误地在polyfills.ts文件中禁用此导入时,出现了此错误,您需要确保将其导入以避免该错误。

/** Evergreen browsers require these. **/
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
import 'core-js/es7/reflect';

2

就我而言,我试图扩展“ NativeDateAdapter”以覆盖“format(date: Date, displayFormat: Object) ”方法。

在AngularMaterial-2 DatePicker中。

所以基本上我忘了添加@Injectable注释。

在将其添加到“ CustomDateAdapter”类后:

@Injectable({
  providedIn: 'root'
})

错误消失了。


这对我有用,但我不知道为什么。是否需要提供服务和通过DI接收服务的组件,才能使DI正常工作?
Mike Furlender

2

这个答案可能对这个问题很有帮助。另外,就我而言,default原因是导出服务。

错误:

@Inject()
export default class MobileService { ... }

正确:

@Inject()
export class MobileService { ... }

2

由于错误反馈不足,这可能是一个很难调试的问题。如果您担心实际的循环依赖关系,那么这是在堆栈跟踪中查看的最重要的内容:a)服务的名称b)该服务中带有问号的构造函数参数,例如:

无法解析AuthService的所有参数:([对象对象],[对象对象],[对象对象],[对象对象] 、?)

则表示第5个参数是也依赖AuthService的服务。即问号,表示DI并没有解决它。

从那里,您只需要通过重组代码来分离这两个服务。


1

我通过错误输入服务名称即构造函数(私有myService:MyService)遇到了此错误。

对于拼写错误的服务,我可以通过检查Chrome-> Console中的页面来确定哪个服务是问题所在(在构造函数中列出了几个)。通过显示对象Object,对象Object,?,您将在消息中看到“参数”数组列表。(或类似的东西)。注意在哪里“?” 是,这就是引起问题的服务位置。


1

虽然订购可能已经提到了从桶中导出类,但以下情况也可能产生相同的效果。

假设你有课ABC从那里同一个文件内出口的A依赖BC

@Injectable()
export class A {
    /** dependencies injected */
    constructor(private b: B, private c: C) {}
}

@Injectable()
export class B {...}

@Injectable()
export class C {...}

由于Angular尚不知道依赖类(即本例中的类BC)(可能是在Angular对类的依赖项注入过程中的运行时A),因此引发了错误。

解决方案是在完成DI的类之前声明并导出相关类。

也就是说,在上述情况下,A在定义其依赖项后立即声明该类:

@Injectable()
export class B {...}

@Injectable()
export class C {...}

@Injectable()
export class A {
    /** dependencies injected */
    constructor(private b: B, private c: C) {}
}

1

就我而言,我是从同一组件文件中导出类和枚举:

mComponent.component.ts

export class MyComponentClass{...}
export enum MyEnum{...}

然后,我尝试MyEnum从的一个孩子使用MyComponentClass。这导致无法解决所有参数错误

通过MyEnumMyComponentClass,解决了我的问题!

正如GünterZöchbauer所提到的,之所以发生这种情况,是因为服务或组件是循环依赖的。


1

如果您的服务与组件(使用它的组件)在同一文件中定义,并且服务在之后定义在文件中的组件则可能会出现此错误。这是由于其他人提到的相同“ forwardRef”问题造成的。目前,VSCode不太适合向您显示此错误,并且编译成功。

--aot由于编译器的工作方式(可能与树抖动有关),运行build with 可以掩盖此问题。

解决方案:确保在另一个文件中或在组件定义之前定义了服务。(我不确定在这种情况下是否可以使用forwardRef,但是这样做似乎很笨拙)。

如果我有一个非常简单的服务,该服务与组件紧密相连(类似于视图模型),例如。ImageCarouselComponent,我可能会为其命名,ImageCarouselComponent.service.ts以便不会与我的其他服务混为一谈。


1

就我而言,这是一个循环引用。我有MyService调用Myservice2和MyService2调用MyService。

不好 :(


1

就我而言,原因如下:

  • 我的注射服务A扩展了另一类B
  • B有一个构造函数,需要一个参数
  • 我没有在A中定义任何构造函数

结果,当尝试创建对象A时,默认构造函数失败。我不知道为什么这不是编译错误。

我通过在A中添加一个构造函数(它正确地称为B的构造函数)来解决此问题。


1

知道了!

如果以上答案均不能帮助您,则可能是您从组件注入服务的同一文件中导入了一些元素。

我会更好地解释:

这是服务文件

// your-service-file.ts
import { helloWorld } from 'your-component-file.ts'

@Injectable()
export class CustomService() {
  helloWorld()
}

这是组件文件

@Component({..})
export class CustomComponent {
  constructor(service: CustomService) { }
}

export function helloWorld() {
  console.log('hello world');
}

因此,即使符号不在同一个组件内,而是在同一个文件内,也会引起问题。将符号(可以是函数,常量,类等)移动到其他位置,错误将消失


1

对于angular 6和更高版本,请尝试

@Injectable({
  providedIn: 'root'
})

..就在您的服务类别上方,中间没有其他任何一行

优点

  • 无需将服务添加到任何模块(将被“自动发现”)
  • 服务将是单例(因为它将被注入到根)

[ angular docs ]

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.