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

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.

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

JP ten Berge
источник
Да, эта ошибка обычно связана с тем, что вы забыли добавить @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

Reactgular
источник
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 { ... }
JMI MADISON
источник
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{
}
HockeyJ
источник
2
В моем случае я добавил дополнительные классы и интерфейсы между @Injectable и определением класса сервиса, поэтому класс сервиса больше не помечался как инъекционный.
Herc
Если вы полностью забудете декоратор @Injectable () для класса обслуживания, который использует другие сервисы для инъекций, то ваш неправильно оформленный сервис также выдаст эту ошибку.
И. Бьюкен
10

В моем случае мне нужно было добавить import "core-js/es7/reflect";в свое приложение, чтобы сделать @Injectableработу.

Эй Джей Ричардсон
источник
9

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

{
  "compilerOptions": {

     ...

    "emitDecoratorMetadata": true,

     ...

    }

}
Stewart_R
источник
8

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

MK
источник
У меня также было это, когда есть зависимость от функции, просто определенной в том же файле. Разделение его на отдельный файл исправило это.
Джо
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
4

В моем случае это было из-за плагина Augury, отключить его будет нормально. Альтернативный вариант есть, тоже работает.

все кредиты @ Boboss74, он разместил ответ здесь: https://github.com/angular/angular/issues/23958

Тинь Данг
источник
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 = [];
    }
}

Я решил это, просто удалив этот аргумент.

Codiee
источник
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 { ... }
otiai10
источник
2

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

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

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

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

sarora
источник
1

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

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

maleman
источник
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так, чтобы он не смешивался с другими моими услугами.

Simon_Weaver
источник
1

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

Фигово :(

lucbonnin
источник
1

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

  • мой инъекционный сервис А продлил еще один класс Б
  • У B был конструктор, который требовал аргумента
  • Я не определил ни одного конструктора в A

Как следствие, при попытке создать объект A конструктор по умолчанию потерпел неудачу. Я понятия не имею, почему это не было ошибкой компиляции.

Я исправил это, просто добавив конструктор в A, который правильно назвал конструктор B.

Vic Seedoubleyew
источник
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'
})

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

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

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

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

lolcatzftw
источник