Creating an interface for an Angular 6 service

I'm currently working on a project using Angular (6.0.7) and I am in the process of creating a service using the new:

@Injectable({
  providedIn: 'root'
})

My question is, how can I specify an interface for dependency injection?


The issue at hand

In my project, I have two services - Authentication.service and SessionStorage.service. I want to inject the session storage service into the authentication service. This can be achieved like this:

constructor(private sessionStorage: SessionStorage) {
}

However, I want to define an interface above these services (to allow for implementing both local storage service and session storage service). Therefore, it makes sense to type the injected class with the interface. Unfortunately, Angular 6 does not support this feature in the same way as Angular 5 and earlier versions.

So, how can I assign a type to the injected class in this global service using my interface?


What I've attempted so far

The typings for Angular services include an InjectableProvider, but it doesn't align with any parameters of the siblings of InjectableProvider, leading to compiler and tslint errors.

@Injectable({
  providedIn: 'root'
}, {provide: IStorageService, useClass: SessionStorage})

Answer №1

To achieve this functionality, utilize the InjectionToken instead of the outdated OpaqueToken

export const AuthenticationProvider = new InjectionToken(
  "AuthenticationProvider",
  { providedIn: "root", factory: () => new CognitoAuthenticationProvider() }
);

...

@Injectable()
export class CognitoAuthenticationProvider implements IAuthenticationProvider {

...

@Injectable({
  providedIn: "root"
})
export class AuthenticationService {
  constructor(
    @Inject(AuthenticationProvider)
    private authenticationProvider: IAuthenticationProvider,
    private http: HttpClient
  ) {}

Answer №2

In order to address this challenge, I utilized the following approach:

app.module.ts

providers: [
  { provide: CustomInterface, useClass: environment.instance }
  ...
]

CustomInterface.ts

export abstract class CustomInterface {
   abstract customMethod();
}

MyImplementation1.ts

export class MyImplementation1 implements CustomInterface {
   customMethod() { ... }; // implementation
}

export class MyImplementation2 implements CustomInterface {
   customMethod() { ... }; // implementation
}

environment.ts

export const environment = {
  production: false,
  instance: MyImplementation2
};

environment.prod.ts

export const environment = {
  production: true,
  instance: MyImplementation1
};

Answer №3

Utilizing typescript interfaces for dependency injection may not be possible as typescript interfaces do not persist during runtime, serving solely for type safety at compile time.
To address this limitation, utilizing an abstract class is recommended.

UPDATE: It appears that the useClass should be used as the first parameter in @Injectable, rather than the second position as demonstrated in your example. By incorporating this with @k0zakinio's solution results in:

@Injectable({
  providedIn: 'root',
  useClass: environment.concrete,
  deps: []
})
export abstract class SessionStorage { }

Additionally, it seems necessary to declare dependencies using deps or inject, refer to this github issue. Hopefully, this revised answer proves to be more helpful.

Answer №4

One way to accomplish this is by using the following syntax -

[{ type: CustomType, implement: CustomImplementation}]

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Drizzle ORM retrieve unique string that is not a database column

I'm working with a SQL query that looks like this: SELECT * FROM ( SELECT 'car' AS type, model FROM car UNION SELECT 'truck' AS type, model FROM trucks ) vehicles; In Drizzle, I'm trying to replicate the 'car ...

Dropdown element with PrimeNG adorned with a span

I am trying to create a simple form with text inputs and dropdowns. I have successfully implemented the textInput, but I am struggling with the dropdowns. Below is the code that I have so far: <div class="p-grid p-dir-col p-offset-2"> ...

Encountering an issue with Angular 8 and Material where a table does not fully render on mobile browsers like Chrome, causing rows to only half

Currently, I have an Angular 8 application integrated with Material v8.2.3 where a table with expanding rows is being used. While everything functions perfectly on desktop browsers, there seems to be an issue when accessing the application on mobile phone ...

Coordinate tab switching in mat-tab-group with a matching component

I have a mat-tab-group within a component called "person". The parent component, named "persons", contains two identical person components, each with 3 tabs in its mat-tab-group. My goal is to have the components synchronized so that when one person switch ...

Firebase and Nx: Encountering issues with running emulators

I've been attempting to launch the Firebase emulators within the Nx workspace. Initially, I added firebase to my project: npm install firebase @angular/fire --save nx g @angular/fire:ng-add // configures the package in the project (unsuccessful) ng ...

What is the process for displaying data within an Angular 10 component?

As I embark on my journey with Angular 10, my goal is to display the current user in the profile.component.html and the navbar in app.component.html. Below you will find the relevant code snippets: users.ts export interface User { username : string ...

The utilization of the Angular date pipe significantly impacts the way dates are

When I use the pipe date:'MM/dd/YYYY' to display the date 2022-01-01T00:00:00, it shows as 1/01/2021 instead of 1/01/2022. This issue only occurs with this specific date. Why does this happen? The value of pharmacyRestrictionDate is 2022-01-01T0 ...

Utilizing TypeScript to export a class constructor as a named function

Imagine you have this custom class: export class PerformActionClass<TEntity> { constructor(entity: TEntity) { } } You can use it in your code like this: new PerformActionClass<Person>(myPersonObject); However, you may want a more co ...

Encountering issues during postinstall when trying to npm install the classlist.js package using

I am facing an issue on Windows 10 with the latest update. My npm version is 5.4.1 and despite trying multiple solutions from various sources like StackOverflow and GitHub, I am unable to resolve it. Some of the things I have tried are: Using command pro ...

Leveraging the power of ReactJS and TypeScript within a Visual Studio environment for an MVC5 project

I am currently working on creating a basic example using ReactJS and TypeScript in Visual Studio 2015. Despite following several tutorials, none of them have met my specific requirements or worked as expected. My goal is to develop components as .tsx fil ...

The service method call does not occur synchronously

In my OrderServer class, I am utilizing an OrderService to connect to a database and retrieve data every minute. The communication with the web app is handled through SocketIO. Here is a snippet of the code: export class OrderServer { // some required fie ...

Detecting unutilized space in a collection of divs with varying sizes using JavaScript and CSS

To better understand my issue, I created a StackBlitz demo: https://stackblitz.com/edit/angular-aqmahw?file=src/app/tiles-example.css Screenshot My tiles can have four different widths (25%, 50%, 75%, 100%). The tiles must fit on only two lines, so if a ...

Implementing Dynamic Updates to a Google Sheets Custom Menu using Typescript

How to Automatically Update a Custom Menu in Google Sheets using Typescript I have successfully set up the following: Dynamically Updating Custom Menu of Google Spreadsheet using Google Apps Script, a demonstration script for dynamically updating the cust ...

What is the best approach to creating a Typescript library that offers maximal compatibility for a wide range

My Vision I am aiming to develop a versatile library that can cater to both JavaScript and TypeScript developers for frontend applications, excluding Node.js. This means allowing JavaScript developers to utilize the library as inline script using <scri ...

Exploring the process of updating the background color of a specific component in Angular

I'm currently working on a website that will feature alternating colors of white and black. However, I am facing an issue where I can only apply background color changes globally in the CSS file. Does anyone know how to address this problem? ...

What is the reason behind typescript making it necessary for me to find a way to set a value of type

function f1() { const v : string = String(); if(v) {alert("IF");} // OK const b : boolean = v; // Type 'string' is not assignable to type 'boolean'. if(b) {alert("BOOLEAN");} } f1(); My approach to this issue involv ...

Exploring the depths of TypeScript's intricate type validation

Could you please review the comments in the code? I am trying to determine if it is feasible to achieve what I need or if TypeScript does not support such functionality. I require type checks for my addToRegistry function. Play around with TypeScript in ...

Tips for integrating angular signature functionality using fabricjs in the latest version of Angular (Angular 11)

After struggling to make paperjs and the angular-signature library work together, I was at my wit's end. But then, I stumbled upon a different solution that proved to be much better. I realized that posting the solution under the appropriate question ...

Using Iframe for WooCommerce integration and implementing Facebook login within an Ionic application

I have created an Ionic application that includes an iframe from a Wordpress website. Here is the code snippet from my home.page.ts file: import { Component } from '@angular/core'; import { DomSanitizer } from "@angular/platform-browser"; @Com ...

Learn how to implement code splitting in a React application with webpack by exporting components using the syntax "export * from '...'"

In my React app, I recently implemented code splitting which has been working well. However, when analyzing the bundle size, I noticed an issue with how my components folder is loaded in the initial chunk. It includes all components, even those that are on ...