Interface 可以用angular2注入接口吗?

Interface 可以用angular2注入接口吗?,interface,angular,inject,Interface,Angular,Inject,我想知道是否有合适的方法在Angular2中注入接口?(参见下文) 我认为这与接口上缺少@Injectable()装饰符有关,但这似乎是不允许的 问候 当CourseServiceInterface作为接口实现时,TypeScript编译器会抱怨“CourseServiceInterface找不到名称”: 但是使用CourseServiceInterface作为接口: import {Injectable} from 'angular2/core'; import {Course} from '

我想知道是否有合适的方法在Angular2中注入接口?(参见下文)

我认为这与接口上缺少@Injectable()装饰符有关,但这似乎是不允许的

问候

当CourseServiceInterface作为接口实现时,TypeScript编译器会抱怨“CourseServiceInterface找不到名称”:

但是使用CourseServiceInterface作为接口:

import {Injectable} from 'angular2/core';
import {Course} from './Course.class';
//@Injectable()
export interface CoursesServiceInterface {
    getAllCourses(): Promise<Course[]>;//{ return null; };
    getCourse(id: number): Promise<Course>;// { return null; };
    remove(id: number): Promise<{}>;// { return null; };
}
从'angular2/core'导入{Injectable};
从“./Course.class”导入{Course};
//@可注射()
导出接口CourseServiceInterface{
getAllCourses():Promise;//{return null;};
getCourse(id:number):Promise;//{returnnull;};
remove(id:number):Promise;//{returnnull;};
}
当服务是一个类时,TypeScript编译器不再抱怨:

import {Injectable} from 'angular2/core';
import {Course} from './Course.class';
@Injectable()
export class CoursesServiceInterface {  
    getAllCourses() : Promise<Course[]> { return null; };
    getCourse(id: number) :Promise<Course> { return null; };
    remove (id: number) : Promise<{}> { return null; };
}
从'angular2/core'导入{Injectable};
从“./Course.class”导入{Course};
@可注射()
导出类CourseServiceInterface{
getAllCourses():承诺{returnnull;};
getCourse(id:number):承诺{returnnull;};
remove(id:number):承诺{returnnull;};
}

否,DI不支持接口。使用TypeScript时,接口在运行时不再可用,只能静态使用,因此不能用作DI令牌

或者,您可以使用字符串作为键或
InjectionToken

provide('CourseServiceInterface',{useClass:CourseServiceMock})//old

提供者:[{provide:'CourseServiceInterface',useClass:CourseServiceMock}]
然后像注射一样注射

构造函数(@Inject('CourseServiceInterface')私有CourseService:CourseServiceInterface){

另请参见使用OpaqueToken,DI不支持接口,因为Javascript本身没有接口。在Angular 2中执行此操作的一种方法是使用OpaqueToken。

我希望这能有所帮助。

我对前端开发的经验(来自java后端开发)如下

如果我们谈论“接口”,我强烈期望“提供”接口的语言能够保证使用接口的主要原则。 这就是:“针对接口而不是实现的代码”

typescript/angular2似乎无法保证这一点。(也许他们还不应该使用word界面)

我的情况是什么(警告:我正在学习angular2,所以我的解决方案对高级用户来说可能很难看):
组件A1有一个子组件B。
组件B应该知道父级并调用父级上的方法。
因此组件B通过其构造函数中的DependencyInjection接收父级

   constructor( private a: A1Component) {}
一切都很好
事情变得复杂了
另一个组件A2可以是comp的父组件。B.
理想情况下,我应该在B中注入一个由A1和A2实现的接口(而不是实现)(这在java世界中是很自然的)。
B将使用此接口。如果需要,例如,将typecast转换为A2将使B知道他拥有的实例是否真的是A2

我说的是普通组件/类,而不是服务(我看到大多数解决方案都是指服务)。
我尝试使用@Host()、@Injectable()、OpaqueToken和Providers,但总是出现错误。最后,它似乎起了作用:实际上,组件B中注入的对象是一个空对象,而不是父对象-可能我错误地使用了提供者,并创建了一个新的空对象,而不是注入父对象

我最后做了什么:我没有使用界面。
我为A1和A2创建了一个简单的基类——我们称之为ABase。
组件B将保留对此基类的引用。引用将在构造函数中设置为:

//BComponent:
 parent: ABase;    

 constructor(@Optional parentA1: A1Component, @Optional parentA2: A2Component) {
    if( parentA1 )
       this.parent = parentA1;
    else
       this.parent = parentA2
 }
是的,这是一个奇怪的解决方法,不太好(来自java世界的思考,我同意)——但我只是没时间了,对“接口”的事情感到失望

更新 我重新考虑了之前的答案(它的设计很糟糕,很难看…在我刚开始使用angular时)

现在Angular的文档已经清楚地描述了这个问题:查找组件的父级

无法使用接口-因为无法注入接口

“寻找实现接口的组件会更好。这是不可能的,因为TypeScript接口会从不支持接口的传输JavaScript中消失。没有可查找的工件。”

两者都不能用。。。(这是我之前绝望、糟糕回答的根本原因)

什么有效?技术:

主要是:

子B查看一般父级
父级
(可以是a1组件或a2组件)

每个可能的父组件都提供一个
父组件(在组件级别!!!),使用:


不能使用接口的原因是接口是TypeScript设计时工件。JavaScript没有接口。TypeScript接口从生成的JavaScript中消失。运行时,Angular无法找到任何接口类型信息


解决方案1:

最简单的解决方案就是定义一个实现接口的抽象类。通常,您需要一个抽象类

接口:

import {Role} from "../../model/role";

export interface ProcessEngine {

     login(username: string, password: string):string;

     getRoles(): Role[];
}
抽象类:

import {ProcessEngine} from "./process-engine.interface";

export abstract class ProcessEngineService implements ProcessEngine {

    abstract login(username: string, password: string): string;

    abstract getRoles(): Role[];

}
混凝土等级:

import { Injectable } from '@angular/core';
import {ProcessEngineService} from "./process-engine.service";

@Injectable()
export class WebRatioEngineService extends ProcessEngineService {

    login(username: string, password: string) : string {...}

    getRoles(): Role[] {...}

}
现在,您可以像往常一样定义提供商:

@NgModule({
      ...
      providers: [
        ...,
        {provide: ProcessEngineService, useClass: WebRatioEngineService}
      ]
})

解决方案2:

Angular的官方文档建议使用,类似于OpaqueToken。以下是一个例子:

您的接口和类:

export interface AppConfig {
   apiEndpoint: string;
   title: string;
}

export const HERO_DI_CONFIG: AppConfig = {
  apiEndpoint: 'api.heroes.com',
  title: 'Dependency Injection'
};
定义您的令牌:

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

export let APP_CONFIG = new InjectionToken<AppConfig>('app.config');
然后,在@inject decorator的帮助下,您可以将配置对象注入到任何需要它的构造函数中:

constructor(@Inject(APP_CONFIG) config: AppConfig) {
     this.title = config.title;
}

角9的替代解决方案

@Injectable()
export class TodoListPublicService implements TodoListService {
  getTodos(): Todo[] {
    const todos: Todo[] = [
      {
        title: 'get groceries',
        description: 'eggs, milk, etc.',
        done: false
      }
    ];

    return todos;
  }
}
创建一个抽象类

export interface Todo {
  title: string;
  description: string;
  done: boolean;
}

@Injectable()
export abstract class TodoListService {
  abstract getTodos(): Todo[];
}
在组件中使用

providers: [
    { provide: TodoListService, useClass: TodoListPublicService }
  ]
export class TodoListComponent implements OnInit {
  todos: Todo[];

  constructor(private todoListService: TodoListService) { }

  ngOnInit() {
  }

对于那些以Angular 4为目标并找到了这个答案的人来说,解决方案2无疑是一条路要走。通过这种设置,可以为单元te注入任何类型的模拟类
providers: [{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }]
constructor(@Inject(APP_CONFIG) config: AppConfig) {
     this.title = config.title;
}
@Injectable()
export class TodoListPublicService implements TodoListService {
  getTodos(): Todo[] {
    const todos: Todo[] = [
      {
        title: 'get groceries',
        description: 'eggs, milk, etc.',
        done: false
      }
    ];

    return todos;
  }
}
export interface Todo {
  title: string;
  description: string;
  done: boolean;
}

@Injectable()
export abstract class TodoListService {
  abstract getTodos(): Todo[];
}
providers: [
    { provide: TodoListService, useClass: TodoListPublicService }
  ]
export class TodoListComponent implements OnInit {
  todos: Todo[];

  constructor(private todoListService: TodoListService) { }

  ngOnInit() {
  }