angular2로 인터페이스를 주입할 수 있습니까?
Angular2에서 인터페이스를 주입하는 적절한 방법이 있는지 궁금합니다. (아래 참조)
인터페이스에 @Injectable() 데코레이터가 누락된 것과 관련이 있다고 생각합니다만, 허용되지 않는 것 같습니다.
안부 전해요.
과정 서비스 시인터페이스가 인터페이스로 구현되면 TypeScript 컴파일러가 "CoursService"에 불만을 제기합니다.인터페이스에서 이름을 찾을 수 없습니다.":
import {CoursesServiceInterface} from './CoursesService.interface';
import {CoursesService} from './CoursesService.service';
import {CoursesServiceMock} from './CoursesServiceMock.service';
bootstrap(AppComponent, [
ROUTER_PROVIDERS,
GlobalService,
provide(CoursesServiceInterface, { useClass: CoursesServiceMock })
]);
그러나 과정 서비스 포함인터페이스로서의 인터페이스:
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; };
}
서비스가 클래스일 때 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; };
}
아니요, DI에는 인터페이스가 지원되지 않습니다.TypeScript 인터페이스는 더 이상 런타임에 사용할 수 없으며 정적으로만 사용되므로 DI 토큰으로 사용할 수 없습니다.
또는 문자열을 키로 사용할 수 있습니다.InjectionToken
provide('CoursesServiceInterface', {useClass: CoursesServiceMock}) // old
providers: [{provide: 'CoursesServiceInterface', useClass: CoursesServiceMock}]
그리고 그것을 주입합니다.
constructor(@Inject('CoursesServiceInterface') private coursesService:CoursesServiceInterface) {}
https://angular.io/api/core/InjectionToken 도 참조하십시오.
인터페이스를 사용할 수 없는 이유는 인터페이스가 TypeScript 디자인 타임 아티팩트이기 때문입니다.자바스크립트에는 인터페이스가 없습니다.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');
주입을 사용하여 종속성 제공자 등록토큰 개체(예: app.module.ts):
providers: [{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }]
@Injectdecorator의 도움을 받아 구성 개체를 필요로 하는 모든 생성자에 주입할 수 있습니다.
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() {
}
Javascript 자체에 인터페이스가 없기 때문에 인터페이스가 DI에서 지원되지 않으므로 OpaqueToken을 사용합니다.Angular 2에서 이를 수행하는 한 가지 방법은 OpaqueToken을 사용하는 것입니다.https://angular.io/docs/ts/latest/guide/dependency-injection.html
import { OpaqueToken } from '@angular/core';
export let APP_CONFIG = new OpaqueToken('app.config');
providers: [{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }]
constructor(@Inject(APP_CONFIG) config: AppConfig) {
this.title = config.title;
}
이것이 도움이 되길 바랍니다.
(자바 백엔드 개발에서 얻은) 프론트엔드 개발 경험은 다음과 같습니다.
만약 우리가 '인터페이스'에 대해 말한다면, 나는 인터페이스를 '제공'하는 언어에 의해 인터페이스를 사용하는 주요 원칙이 보장될 것이라는 강한 기대를 가지고 있습니다.즉, '인터페이스에 대한 코드는 구현에 대한 코드가 아닙니다'입니다.
이것은 유형 스크립트/각도2로는 확신할 수 없는 것 같습니다.(아마도 아직 워드 인터페이스를 사용해서는 안 될 것입니다.)
이었을까 ( 나는 내 수 고급 사용자가 보기에 해결 방법이 보기 흉할 수 있도록 angular2를 배우고 있습니다.):
구성 요소 A1에는 하위 구성 요소 B가 있습니다.
구성 요소 B는 상위를 알고 상위에서 메서드를 호출해야 합니다.
구성 B는 종속성 B속을통해상위수항다신니합목따을성종을 통해 .그것의 생성자에 주입.
constructor( private a: A1Component) {}
모든 것이 좋습니다.
일이 복잡해지는 것보다.
또 다른 구성요소 A2는 B사의 모체가 될 수 있습니다.
이상적으로는 A1과 A2 모두에 의해 구현되는 Ban 인터페이스(구현이 아닌)를 삽입해야 합니다(이것은 자연스럽게 자바 세계에 있을 것입니다).
B는 이 인터페이스에서 작동합니다.필요한 경우 예를 들어 A2로 A타입캐스트를 하면 B가 가진 인스턴스가 정말 A2인지 알 수 있습니다.
저는 서비스가 아닌 일반 구성요소/클래스에 대해 이야기합니다(대부분의 솔루션은 서비스를 참조합니다).
@Host(), @Injectionable(), OpaqueToken, Providers는 호스트 이름입니다.결국 작동하는 것처럼 보였을 때: 실제로 구성 요소 B에 주입된 개체는 부모가 아닌 빈 개체였습니다. 공급자를 잘못 사용하여 부모 개체를 주입하는 대신 새로운 빈 개체가 생성되었을 수 있습니다.
결국 제가 한 일은 인터페이스를 사용하지 않았습니다.
저는 A1과 A2를 위한 플레인 베이스 클래스를 만들었습니다 - 그것을 Base라고 부르자.
구성 요소 B는 이 기본 클래스에 대한 참조를 유지합니다.생성자에서 참조는 다음과 같이 설정됩니다.
//BComponent:
parent: ABase;
constructor(@Optional parentA1: A1Component, @Optional parentA2: A2Component) {
if( parentA1 )
this.parent = parentA1;
else
this.parent = parentA2
}
네, 이상한 해결 방법입니다. 좋지 않습니다. (Java World의 생각에서 나온 것입니다. 동의합니다.) 하지만 저는 시간이 부족해서 '인터페이스'에 빠졌습니다.
업데이트됨
저는 이전 답변을 다시 생각합니다(나쁜 디자인, 추악함... 처음에는 각진 상태였습니다).
이제 Angular의 문서에는 구성 요소의 상위 항목 찾기라는 정확한 문제에 대한 명확한 설명이 있습니다.
인터페이스를 사용할 수 없습니다. 인터페이스를 주입할 수 없습니다.
"인터페이스를 구현하는 구성 요소를 찾는 것이 더 나을 것입니다.TypeScript 인터페이스가 인터페이스를 지원하지 않는 tiled JavaScript에서 사라지기 때문에 불가능합니다.찾을 만한 유물이 없습니다."
가능한 부모의 기본 클래스도 사용할 수 없습니다...(이것이 내가 이전에 절망적이고, 나쁜 대답을 한 근본 원인입니다.)
무엇이 효과가 있습니까?매개 변수: 클래스 인터페이스를 사용하여 부모를 찾습니다.
주로:
자녀 B 일반 부모 보기Parent
(A1 구성 요소 또는 A2 구성 요소일 수 있음)
export class BComponent {
name = 'B';
constructor( @Optional() public parent: Parent ) { }
}
그리고 각각의 가능한 부모 구성요소는Parent
(구성요소 수준에서!!) 클래스 인터페이스 사용:
providers: [{ provide: Parent, useExisting: forwardRef(() => A1Component) }],
저도 비슷한 문제를 발견했기 때문에 여기에 몇 센트를 남길 것입니다(하지만 v10).서비스에 의존성으로 추상 클래스를 제공하는 대신 인터페이스를 사용했습니다.나는 의존성 서비스에 그것을 주입하여 그것을 해결할 수 있었습니다.@Inject()
class DependencyService implements IDependency {}
class SomeDataService {
constructor(@Inject('IDependency') private readonly service: IDependency) {}
}
그리고 이 서비스에 의존한 구성 요소에서.
@Component({
providers: [
SomeDataService,
{
provide: 'IDependency',
useClass: DependencyService,
}
]
})
export class ListComponent {
constructor(private readonly someDataService: SomeDataService) {}
}
저의 "꼼수"는 구성 요소에 인터페이스를 선언하지만 클래스를 주입하는 것입니다.이렇게 하면 해당 유형 스크립트에서 구성 요소가 인터페이스만 사용할 수 있습니다.
/**
* The official Interface to my Store
*/
interface Store {
readonly hello: string;
readonly theAnswer: number;
doSomething(): void;
}
여기 서비스입니다.
import { Component, Injectable } from "@angular/core";
/**
* The implementation with potentially public members nobody should see
* but may be needed to implement the service...
*/
@Injectable({ providedIn: "root" })
export class StoreService implements Store {
readonly hello = "world";
readonly theAnswer = 42;
doSomething() {}
otherStuff() {}
}
서비스 인터페이스를 사용하는 구성 요소
@Component({
selector: "my-component",
template: `<span>{{ store.hello }}</span>`,
})
export class MyComponent {
/**
* This is what we use
*/
readonly store: Store;
/**
* Here we inject the entire store, but we will only use the interface
* @param store
*/
constructor(store: StoreService) {
this.store = store;
}
}
추가적인 이점은 단일 스토어가 여러 인터페이스를 구현할 수 있다는 것입니다(예:Pick
) 및 구성 요소는 내부적으로 필요한 것을 사용합니다.
@Component({
selector: "my-other-component",
template: `<span>{{ store.theAnswer }}</span>`,
})
export class MyOtherComponent {
/**
* Here we use only a subset of the store
*/
readonly store: Pick<Store, "theAnswer">;
constructor(store: StoreService) {
this.store = store;
}
}
언급URL : https://stackoverflow.com/questions/37002522/is-it-possible-to-inject-interface-with-angular2
'programing' 카테고리의 다른 글
ReferenceError: Firefox에서 이벤트가 정의되지 않았습니다. (0) | 2023.08.23 |
---|---|
서브모듈 내부의 Git 서브모듈(내포 서브모듈) (0) | 2023.08.23 |
jQuery에서 버튼 클릭 이벤트를 처리하는 방법? (0) | 2023.08.23 |
프로비저닝 프로파일 갱신 (0) | 2023.08.23 |
레이블과 텍스트 영역을 정렬하려면 어떻게 해야 합니까? (0) | 2023.08.23 |