2016-05-03 14 views
20

मुझे आश्चर्य है कि Angular2 में इंटरफेस इंजेक्षन करने का कोई उचित तरीका है या नहीं? (नीचे सीएफ)क्या कोणीय 2 के साथ इंटरफेस इंजेक्ट करना संभव है?

मुझे लगता है कि यह इंटरफ़ेस पर अनुपलब्ध @ इंजेक्टेबल() सजावट से संबंधित है, लेकिन ऐसा लगता है कि इसकी अनुमति नहीं है।

सम्मान।

जब CoursesServiceInterface एक अंतरफलक के रूप में लागू किया जाता है, टाइपप्रति संकलक शिकायत "CoursesServiceInterface नाम नहीं मिल सकता है":

import {CoursesServiceInterface} from './CoursesService.interface'; 
import {CoursesService} from './CoursesService.service'; 
import {CoursesServiceMock} from './CoursesServiceMock.service'; 
bootstrap(AppComponent, [ 
    ROUTER_PROVIDERS, 
    GlobalService, 
    provide(CoursesServiceInterface, { useClass: CoursesServiceMock }) 
    ]); 

लेकिन एक अंतरफलक के रूप CoursesServiceInterface साथ:

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; }; 
} 

जब सेवा एक वर्ग है, टाइपस्क्रिप्ट कंपाइलर अब शिकायत नहीं करता है:

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; }; 
} 

उत्तर

39

नहीं, इंटरफेस DI के लिए समर्थित नहीं हैं। टाइपस्क्रिप्ट इंटरफेस अब रनटाइम पर उपलब्ध नहीं हैं, केवल स्थिर रूप से और इसलिए डी टोकन के रूप में उपयोग नहीं किया जा सकता है।

वैकल्पिक रूप से आप या कुंजी के रूप में तार का उपयोग कर सकते InjectionToken

provide('CoursesServiceInterface', {useClass: CoursesServiceMock}) // old 

providers: [{provide: 'CoursesServiceInterface', useClass: CoursesServiceMock}] 

और

है जैसे कि यह इंजेक्षन

भी देखें https://angular.io/api/core/InjectionToken

+0

useClass: था कि मैं क्या याद आ रही थी ... बहुत बुरा है कि सरकारी ट्यूटोरियल – Aligned

+1

https://angular.io/docs/ts/ में नहीं है नवीनतम/कुकबुक/निर्भरता-इंजेक्शन.html #! # उपयोग करें –

2

उपयोग OpaqueToken, इंटरफेस डि द्वारा समर्थित नहीं हैं, beacause स्वयं Javascript नहीं इंटरफेस है। एंगुलर 2 में ऐसा करने का एक तरीका ओपेक टोकन का उपयोग कर है। 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; 
} 

मुझे आशा है कि यह कर सकते हैं।

+0

ओपैक टोकन को एंगुलर वी 5 में हटा दिया गया है, '' 'इंजेक्शन टोकन '' प्रतिस्थापन – Ryan

-2

मेरा अनुभव (जावा बैकएंड विकास से आ रहा है) फ्रंटेंड देव में निम्नलिखित है।

अगर हम 'इंटरफ़ेस' के बारे में बात करते हैं तो मुझे मजबूत उम्मीद है कि इंटरफ़ेस का उपयोग करने का मुख्य सिद्धांत उन भाषाओं द्वारा आश्वासन दिया जाता है जो 'ऑफ़र' इंटरफेस करते हैं। कौन सा है: 'इंटरफेस के खिलाफ कोड कार्यान्वयन के खिलाफ नहीं है'।

ऐसा लगता है कि टाइपस्क्रिप्ट/कोणीय 2 द्वारा आश्वासन नहीं दिया जाता है। (वे अभी तक शब्द इंटरफ़ेस का उपयोग नहीं करना चाहिए, शायद)।

क्या मेरे मामले था (चेतावनी: मैं angular2 सीख रहा हूँ तो मेरे तरीके को उन्नत उपयोगकर्ताओं के लिए बदसूरत लग सकता है):
घटक A1 एक बच्चे घटक बी
घटक बी माता-पिता जानते हैं और पर एक विधि फोन करना चाहिए है माता-पिता।
तो घटक बी माता-पिता को इसके कन्स्ट्रक्टर में निर्भरता इंजेक्शन के माध्यम से प्राप्त करता है।

constructor(private a: A1Component) {} 

सब कुछ ठीक है।
चीजों की तुलना में जटिल हो जाता है।
एक और घटक ए 2 कॉम्प के माता-पिता हो सकता है। बी
आदर्श रूप में मुझे बी में एक इंटरफेस (कार्यान्वयन नहीं) इंजेक्शन देना चाहिए जो ए 1 और ए 2 दोनों द्वारा लागू किया गया है (यह स्वाभाविक रूप से जावा दुनिया में होगा)।
थान बी इस इंटरफ़ेस के साथ काम करेगा। यदि आवश्यक हो, उदाहरण के लिए ए 2 के लिए एक टाइपकास्ट बी को जागरूक करेगा यदि उसके पास उदाहरण वास्तव में ए 2 है या नहीं।

मैं सादे घटकों/कक्षाओं के बारे में बात करता हूं, सेवाओं नहीं (मुझे लगता है कि अधिकांश समाधान सेवाओं को संदर्भित करते हैं)।
मैंने @ होस्ट(), @ इंजेक्टेबल(), ओपेक टोकन, प्रदाता का उपयोग करने की कोशिश की लेकिन हमेशा एक त्रुटि हुई। अंत में यह काम करने लग रहा था: हकीकत में घटक बी में इंजेक्शन वाली वस्तु एक खाली वस्तु थी, माता-पिता नहीं - शायद मैं गलत प्रदाताओं के लिए प्रयुक्त होता था और मूल वस्तु को इंजेक्ट करने के बजाय एक नई खाली वस्तु बनाई गई थी।

मैंने के अंत में क्या किया: मैंने इंटरफ़ेस का उपयोग नहीं किया।
मैंने ए 1 और ए 2 के लिए एक सादा बेस क्लास बनाया - चलो इसे ABase कहते हैं।
घटक बी इस बेस क्लास का संदर्भ रखेगा। संदर्भ के रूप में निर्माता में निर्धारित किया जाएगा:

//BComponent: 
parent: ABase;  

constructor(@Optional parentA1: A1Component, @Optional parentA2: A2Component) { 
    if(parentA1) 
     this.parent = parentA1; 
    else 
     this.parent = parentA2 
} 

हाँ, यह एक अजीब वैकल्पिक हल, नहीं अच्छा है (जावा दुनिया सोच से आ रही, मैं मानता हूँ) - लेकिन मैं सिर्फ समय समाप्त होने और 'इंटरफ़ेस के बारे में निराश था ' चीज़।

22

कारण आप इंटरफेस का उपयोग नहीं कर सकते हैं क्योंकि एक इंटरफेस एक टाइपस्क्रिप्ट डिज़ाइन-टाइम आर्टिफैक्ट है। जावास्क्रिप्ट में इंटरफेस नहीं है। टाइपस्क्रिप्ट इंटरफ़ेस जेनरेट की गई जावास्क्रिप्ट से गायब हो जाता है। रनटाइम पर खोजने के लिए कोणीय के लिए कोई इंटरफ़ेस प्रकार की जानकारी नहीं छोड़ी गई है।


समाधान 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:

कोणीय की आधिकारिक दस्तावेज InjectionToken, 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 में InjectionToken वस्तु, जैसे का उपयोग कर निर्भरता प्रदाता रजिस्टर:

providers: [{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }] 

इससे पहले कि आप किसी भी निर्माता को कॉन्फ़िगरेशन ऑब्जेक्ट को इंजेक्ट कर सकें यह एक @Inject डेकोरेटर की मदद से:

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

के रूप में एंगुलर 4 को लक्षित करने वालों के लिए, जिन्होंने यह उत्तर पाया है, समाधान 2 निश्चित रूप से रास्ता है जाना। इस सेटअप के साथ, यूनिट परीक्षण के लिए किसी भी तरह के नकली कक्षाओं को इंजेक्शन दिया जा सकता है और जैसे 'प्रदाताओं' को 'प्रदाताओं' जैसे कुछ में बदलकर: [{प्रदान करें: APP_CONFIG, useClass: AppConfigMockClass}] ' – Weikardzaena

+1

यह शानदार है। त्वरित ध्यान दें कि यदि आप इंटरफ़ेस के समान फ़ाइल में टोकन को परिभाषित करते हैं, तो आपको अनावश्यक चेतावनियां मिल सकती हैं: https://github.com/angular/angular-cli/issues/2034 – EvanM

+0

@Weikardzaena परीक्षण के लिए, क्या आप प्रदाताओं को बदलते हैं वास्तविक ऐप मॉड्यूल में, या इन्हें परीक्षणों में स्वयं सेट किया जा सकता है (या पर्यावरण का उपयोग जैसे परीक्षण, देव, प्रोड)? – Ryan

संबंधित मुद्दे