I have an authentication library designed to keep auth stuff consistent across various webapps, inspired by the angular-oauth2-oidc library. I am running into an issue when testing my app, however. In the implemented auth service (employee-auth.service.ts), which extends the library auth service, I get a "ReferenceError: AuthLibConfig is not defined."
I finally discovered that the issue was that the import of the library config, at the behest of eslint, is type only. I am looking for some insight on why a type only import is not sufficient and why it is causing this reference error.
This does not work, but satisfies eslint
import { AUTH_CONFIG_TOKEN, type AuthLibConfig, AuthLibService } from '../auth-lib';
This does work, but yields an eslint error
import { AUTH_CONFIG_TOKEN, AuthLibConfig, AuthLibService } from '../auth-lib';
Here's a stackblitz and directions to reproduce:
https://stackblitz.com/edit/stackblitz-starters-n8o79p
Wait for Stackblitz container to install deps
I am using ng-mocks; I was worried about it being a bug with their MockBuilder, but I stripped it all out for a stock angular unit test and it didn't make a difference.
I've tried providing the AuthLibConfig in the test and creating an instance of the AuthLibConfig directly in the test, but it still remains undefined.
So, TS understands AuthLibConfig
is only used as a type
in that specific file, but we know AuthLibConfig
is more than just a type
as per its usage across the project. So we cannot export it as type
If we import it as type
, AuthLibConfig
references in that file are not processed at test runtime and it is disconnected from its actual bundled definition, thereby resulting in test failure.
It is like a tug of war between TS focusing on the single file vs Angular focusing on the whole project, and neither is willing to give up how they function without a fight.
Option 1: Relax the TS eslint rules for consistent-type-imports but it can cause issues if future code is not handled properly.
(or)
Option 2: Rewrite the injected services using inject
method as below,
FROM
...
export class EmployeeAuthService extends AuthLibService<Employee> {
public constructor(
@Inject(HttpClient) private readonly http: HttpClient,
@Inject(OAuthService) oauth: OAuthService,
@Inject(AUTH_CONFIG_TOKEN) config: AuthLibConfig
) {
super(oauth, config);
}
...
}
TO
import { inject } from '@angular/core'
...
export class EmployeeAuthService extends AuthLibService<Employee> {
private readonly http = inject(HttpClient)
oauth = inject(OAuthService)
config = inject(AUTH_CONFIG_TOKEN)
...
}
This will remove the need for using AuthLibConfig
as type
. But you may have to change it on all files, for better consistency/readability.