ИСКЛЮЧЕНИЕ: не удается разрешить все параметры


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(баррель)? Можете ли вы попробовать импортировать его из файла, в котором он объявлен напрямую?
Гюнтер Цохбауэр

Чудесным образом это, кажется, исправило это! Странно, что это не сработает при использовании ствола, когда другие компоненты, с которыми я тестировал сервис, работали. Если вы хотите опубликовать это как ответ вместо комментария, я приму это.
Кит Отто

11
Вообще круговая зависимость.
Гари

У меня была эта проблема с круговой зависимостью, а также. Стоит отметить, что более новые версии веб-пакета гораздо лучше говорят вам об этом
Энн

Выглядит как круговая зависимость, если вы используете angular> = 4, так что вы можете избавиться от intex.ts (баррель) и импортировать все, что вам нужно напрямую.
Раммгарот

Ответы:


457

Импортируйте его из файла, в котором он объявлен напрямую, а не в бочку.

Я не знаю, что именно вызывает проблему, но я видел, что она упоминалась несколько раз (возможно, какая-то круговая зависимость).

Это также должно быть исправлено путем изменения порядка экспорта в бочке (не знаю деталей, но также упоминалось)


16
это правильно, если у вас есть, например, сервис, внедренный в другой сервис, который должен быть первым в бочке.
Жоао Гарин

17
Команда Angular2 больше не рекомендует бочки из-за множества таких проблем. Рад слышать, что я мог помочь :)
Гюнтер Цохбауэр

13
Не знал, что команда Angular 2 не рекомендует бочки. Если это так, они должны отметить, что в глоссарии обсуждается их польза. И такие проекты, как angular2-webpack-starter, не должны их использовать.
Синий,

3
Это швы, это было исправлено (не проблема в 2.0.2). Я нахожу бочки все еще полезными, особенно когда мне нужно импортировать несколько моделей и сервисов между различными модулями. Это import { cleanValues, getState, FirebaseService, NotificationService, ... } from '../../shared/services';было болью, когда это не сработало ( NgModuleне помогает синглтон-сервис ...
Sasxa

3
Я решил это, изменив порядок экспорта в файле барреля (index.ts). Большое вам спасибо
Спок

331

В дополнение к предыдущим ответам кажется, что эта ошибка также генерируется, когда в вашей инъекционной службе отсутствует фактический @Injectable()декоратор. Поэтому, прежде чем отлаживать функцию циклической зависимости и порядок импорта / экспорта, выполните простую проверку, действительно ли определена ваша служба @Injectable().

Это относится к текущей версии Angular, Angular 2.1.0.

Я открыл вопрос по этому вопросу .


Да, эта ошибка обычно связана с тем, что вы забыли добавить @Injectable, и, например, вы, возможно, просто импортируете Routerиз '@ angular / router', и без этого инъекция эта ошибка всегда будет происходить (как только вы решите сделать одну строку код использует тот
внедренный

Удивительный ответ, моя проблема была в том, что я добавил метод в свою службу и не добавил точку с запятой после последней скобки. Я понятия не имею, почему так должно быть, но в классах компонентов это не так ... сейчас я только рад двигаться дальше!
egimaben

У меня была простая модель, которая дала мне эту ошибку. Я использовал ярлык, где вы создаете свои свойства в конструкторе модели. Типы свойств были только string и int. Затем внезапно эта проблема начала возникать. Добавление @Injectable () решило проблему. Странно, потому что ни одна из моих других моделей не добавила Injectable. Я должен добавить, что я обновил довольно много библиотек перед добавлением этой новой модели. Возможно, как-то связано с этим, но сейчас работает. Спасибо.
Мутоно

@ Мутоно Верно. При пустом конструкторе в вашем сервисе внедрение зависимостей, похоже, не срабатывает и @injectable()не требуется. Что является еще одной странностью для себя. Для хорошей меры я все еще добавил бы это, просто для того, когда вы когда-нибудь решите ввести что-то.
JP Ten Berge

Имейте в виду, что если у вашего сервиса есть базовый класс, который тоже должен быть украшен @Injectable ()
Сэм Шайлс

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 Manual: ForwardRef

Форвард ссылки в Angular 2


3
forwardRef()был уже в альфе ;-) Это необходимо, только если Mobileсервис объявлен ниже в том же файле. Если классы находятся в разных файлах, нет необходимостиforwardRef()
Гюнтер Цохбауэр

4
Гюнтер Цохбауэр, я все еще пытаюсь выяснить реальную проблему с моим кодом, но тем временем forwardRef()помог избавиться от Can't resolve all parameters for ...сообщения. По крайней мере, компонент работает, пока я ищу более подходящее решение проблемы. (И да, ошибочная зависимость импортируется непосредственно из ее файла)
Nik

4
@ GünterZöchbauer Я обновил свой ответ ссылками. Я не пытаюсь отнять у вас ответ, но это на самом деле решает проблему, и люди должны знать об этом. Если вы гуглите вопрос, нет результатов, которые скажут использовать forwardRef. Это очень трудно найти. Вчера у меня ушёл целый день, чтобы решить эту проблему.
Reactgular

Weird. Я опубликовал по крайней мере дюжину ответов, которые предлагают использовать foreardRefсебя, но не больше после того, как NgModuleбыл представлен. Я не беспокоюсь о потере повторений. Мне просто любопытно, почему вы столкнулись с этим после того, как это больше не появлялось в течение нескольких месяцев. Я посмотрю поближе, когда вернусь домой через несколько дней. Большое спасибо за отзыв.
Гюнтер Цохбауэр

2
Если кто-то также заблудился об импорте: import {Component, Inject, ForwardRefFn, forwardRef} из '@ angular / core';
Натанаэль

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: строчная буква «я»:

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

Ошибка № 5: Вы забыли: импортировать {Injectable} из '@ angular / core';

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

ПРАВИЛЬНЫЙ:

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

27

Как уже говорилось, проблема вызвана экспортным заказом внутри ствола, который вызван круговыми зависимостями.

Более подробное объяснение здесь: https://stackoverflow.com/a/37907696/893630


3
Заказ не решил мою проблему. Не используя ствол сделал.
Майкл

21

Я также столкнулся с этим, вводя службу A в службу B и наоборот.

Я думаю, что это хорошо, что это быстро терпит неудачу, так как этого, вероятно, следует избегать в любом случае . Если вы хотите, чтобы ваши услуги были более модульными и могли использоваться повторно, лучше избегать циклических ссылок в максимально возможной степени. Этот пост освещает подводные камни, связанные с этим.

Поэтому у меня есть следующие рекомендации:

  • Если вы чувствуете, что классы взаимодействуют слишком часто (я говорю о зависти к функциям ), вы можете рассмотреть возможность объединения двух сервисов в один класс .
  • Если вышеперечисленное не работает для вас, рассмотрите возможность использования третьего сервисаEventService), который оба сервиса могут внедрить для обмена сообщениями.

1
Это определенно то, что случилось со мной, и это путь. Если вы знаете, что у вас есть несколько служб, требующих обновления, используйте EventService. Он более расширяемый, поскольку вам, несомненно, придется задействовать эти события при расширении приложения на основе этих событий.
themightybun

17

В интересах искателей; Я получил эту ошибку. Это был просто пропущенный символ @.

Т.е. это выдает Can't resolve all parameters for MyHttpServiceошибку.

Injectable()
export class MyHttpService{
}

Добавление отсутствующего @символа исправляет это.

@Injectable()
export class MyHttpService{
}

2
В моем случае я добавил дополнительные классы и интерфейсы между @Injectable и определением класса сервиса, поэтому класс сервиса больше не помечался как инъекционный.
Herc

Если вы полностью забудете декоратор @Injectable () для класса обслуживания, который использует другие сервисы для инъекций, то ваш неправильно оформленный сервис также выдаст эту ошибку.
И. Бьюкен


9

Другая возможность - не emitDecoratorMetadataустанавливать значение true в tsconfig.json.

{
  "compilerOptions": {

     ...

    "emitDecoratorMetadata": true,

     ...

    }

}

8

Эта ошибка появляется, если у вас есть служба A, которая зависит от статического свойства / метода службы B, а сама служба B зависит от службы A через внедрение зависимостей. Так что это своего рода циклическая зависимость, хотя это не так, поскольку свойство / метод является статическим. Вероятно, ошибка, которая возникает в сочетании с AOT .


У меня также было это, когда есть зависимость от функции, просто определенной в том же файле. Разделение его на отдельный файл исправило это.
Джо

1
Спасибо, что упомянули это. Я оказался в точной ситуации. Я не осознавал, что прямой доступ к статическим классам может иметь какое-то отношение к DI. У меня была такая схема: A -> Bи они оба использовали один и тот же статический класс. Решение с помощью forwardRef, но я собираюсь посмотреть, как это можно распутать. Я, вероятно, попытаюсь сделать реальный сервис из этого статического класса (это также приведет к лучшему дизайну).
Слава Фомин 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. Proper - это @Injectable ()


Или в моем случае случайно удалить @
TDP

4

Удаление параметров из метода injectable constructor () решило проблему для моего случая.


Это тоже была моя проблема. Я пришел, чтобы опубликовать это, но обнаружил, что вы сделали первым! +1
17

тогда как отправить параметры в сервис многоразового использования?
3gwebtrain


2

Ну, для меня проблема была еще более раздражающей, я использовал службу внутри службы и забыл добавить ее в качестве зависимости в appModule! Надеюсь, это поможет кому-то сэкономить несколько часов, ломая приложение только для того, чтобы восстановить его снова


1
Я просто пропустил @Injectаннотацию. Я упускал из виду именно то, что сообщение об ошибке говорит немного. Если вы не подозреваете о циклических зависимостях, просто перейдите к классу, указанному в ошибке, и посмотрите на все параметры конструктора и всех членов класса, помеченных комментариями, @Injectи убедитесь, что вы делаете DI правильно для всех них. Подробнее о DI здесь: angular.io/docs/ts/latest/guide/dependency-injection.html
Александр Тейлор

2

Вы должны добавить массив провайдеров в @Component decorator или в модуль, где объявлен ваш компонент. Внутри компонента вы можете сделать, как показано ниже:

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

2

В моем случае, передача неправильных параметров в конструктор генерирует эту ошибку, основная идея этой ошибки заключается в том, что вы неосознанно передали некоторые неправильные аргументы любой функции.

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?
Майк Фурлендер

2

Этот ответ может быть очень полезным для этой проблемы. Кроме того, для моего случая, экспорт услуг, как это defaultбыло причиной.

НЕПРАВИЛЬНО:

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

ПРАВИЛЬНЫЙ:

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

2

Это может быть действительно трудной проблемой для устранения из-за отсутствия обратной связи в ошибке. Если вас беспокоит фактическая циклическая зависимость, вот самое важное, что нужно посмотреть в трассировке стека: а) имя службы; б) параметр конструктора в этой службе, который имеет вопросительный знак, например, выглядит ли он следующим образом:

не удается разрешить все параметры для AuthService: ([объект объекта], [объект объекта], [объект объекта], [объект объекта],?)

тогда это означает, что 5-й параметр является сервисом, который также зависит от AuthService. т.е. вопросительный знак означает, что он не был решен DI.

Оттуда вам просто нужно отделить 2 службы путем реструктуризации кода.


1

Я столкнулся с этой ошибкой, набрав неправильно имя службы, то есть конструктор (private myService: MyService ).

Для сервисов с ошибками я смог определить, какой сервис был проблемой (у меня их было несколько в конструкторе), просмотрев страницу в Chrome-> Консоль. Как часть сообщения вы увидите список массивов параметров с отображением объекта Object, Object Object,? (или что-то типа того). Обратите внимание, где "?" и это позиция службы, которая вызывает проблему.


1

Хотя порядок возможно, упоминалось экспортируемых классов из бочек, следующий сценарий также может дать тот же эффект.

Предположим , у вас есть классы A, Bи Cэкспортируются из того же файла , в котором Aзависит от Bи C:

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

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

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

Поскольку зависимые классы (т.е. в этом случае классы Bи C) еще не известны Angular, ( вероятно, во время выполнения во время процесса внедрения зависимостей 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

В моем случае я экспортировал Class и Enum из одного файла компонента:

mComponent.component.ts:

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

Затем я пытался использовать MyEnumот ребенка MyComponentClass. Это приводило к ошибке « Не удается разрешить все параметры» .

Переместившись MyEnumв отдельную папку MyComponentClass, это решило мою проблему!

Как отметил Гюнтер Цохбауэр, это происходит из-за того, что услуга или компонент циклически зависимы.


1

Если ваша служба определена в том же файле, что и компонент (который ее использует), а служба определяется после компонента в файле, вы можете получить эту ошибку. Это связано с той же проблемой 'forwardRef', о которой упоминали другие. В настоящее время VSCode не очень хорошо показывает эту ошибку, и сборка успешно компилируется.

Запуск сборки с помощью --aotможет скрыть эту проблему из-за того, как работает компилятор (возможно, это связано с дрожанием дерева).

Решение. Убедитесь, что служба определена в другом файле или перед определением компонента. (Я не уверен, можно ли использовать forwardRef в этом случае, но это кажется неуклюжим).

Если у меня есть очень простой сервис, который очень сильно привязан к компоненту (вроде как модель представления) - например. ImageCarouselComponentЯ могу назвать его ImageCarouselComponent.service.tsтак, чтобы он не смешивался с другими моими услугами.


1

В моем случае это была круговая ссылка. У меня был MyService, вызывающий Myservice2, и MyService2, вызывающий MyService.

Фигово :(


1

В моем случае причина была следующая:

  • мой инъекционный сервис А продлил еще один класс Б
  • У 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

для угловых 6 и более новых версий, попробуйте

@Injectable({
  providedIn: 'root'
})

.. прямо над вашим классом обслуживания без других линий между ними

преимущества

  • нет необходимости добавлять службу в какой-либо модуль (будет автоматически обнаружен)
  • сервис будет одноэлементным (так как он будет внедрен в корень)

[ угловые документы ]

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.