1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-14 07:13:32 +00:00

[AC-2278] [AC-2296] Use SafeProvider in browser services module (#8418)

This commit is contained in:
Thomas Rittson
2024-03-28 08:28:51 +10:00
committed by GitHub
parent 5cb2e99b2f
commit b3b344866e
5 changed files with 381 additions and 361 deletions

View File

@@ -4,7 +4,7 @@ import { Constructor, Opaque } from "type-fest";
import { SafeInjectionToken } from "../../services/injection-tokens";
/**
* The return type of our dependency helper functions.
* The return type of the {@link safeProvider} helper function.
* Used to distinguish a type safe provider definition from a non-type safe provider definition.
*/
export type SafeProvider = Opaque<Provider>;
@@ -18,12 +18,22 @@ type MapParametersToDeps<T> = {
type SafeInjectionTokenType<T> = T extends SafeInjectionToken<infer J> ? J : never;
/**
* Gets the instance type from a constructor, abstract constructor, or SafeInjectionToken
*/
type ProviderInstanceType<T> =
T extends SafeInjectionToken<any>
? InstanceType<SafeInjectionTokenType<T>>
: T extends Constructor<any> | AbstractConstructor<any>
? InstanceType<T>
: never;
/**
* Represents a dependency provided with the useClass option.
*/
type SafeClassProvider<
A extends AbstractConstructor<any>,
I extends Constructor<InstanceType<A>>,
A extends AbstractConstructor<any> | SafeInjectionToken<any>,
I extends Constructor<ProviderInstanceType<A>>,
D extends MapParametersToDeps<ConstructorParameters<I>>,
> = {
provide: A;
@@ -40,37 +50,25 @@ type SafeValueProvider<A extends SafeInjectionToken<any>, V extends SafeInjectio
};
/**
* Represents a dependency provided with the useFactory option where a SafeInjectionToken is used as the token.
* Represents a dependency provided with the useFactory option.
*/
type SafeFactoryProviderWithToken<
A extends SafeInjectionToken<any>,
I extends (...args: any) => InstanceType<SafeInjectionTokenType<A>>,
D extends MapParametersToDeps<Parameters<I>>,
> = {
provide: A;
useFactory: I;
deps: D;
};
/**
* Represents a dependency provided with the useFactory option where an abstract class is used as the token.
*/
type SafeFactoryProviderWithClass<
A extends AbstractConstructor<any>,
I extends (...args: any) => InstanceType<A>,
type SafeFactoryProvider<
A extends AbstractConstructor<any> | SafeInjectionToken<any>,
I extends (...args: any) => ProviderInstanceType<A>,
D extends MapParametersToDeps<Parameters<I>>,
> = {
provide: A;
useFactory: I;
deps: D;
multi?: boolean;
};
/**
* Represents a dependency provided with the useExisting option.
*/
type SafeExistingProvider<
A extends Constructor<any> | AbstractConstructor<any>,
I extends Constructor<InstanceType<A>> | AbstractConstructor<InstanceType<A>>,
A extends Constructor<any> | AbstractConstructor<any> | SafeInjectionToken<any>,
I extends Constructor<ProviderInstanceType<A>> | AbstractConstructor<ProviderInstanceType<A>>,
> = {
provide: A;
useExisting: I;
@@ -84,31 +82,26 @@ type SafeExistingProvider<
*/
export const safeProvider = <
// types for useClass
AClass extends AbstractConstructor<any>,
IClass extends Constructor<InstanceType<AClass>>,
AClass extends AbstractConstructor<any> | SafeInjectionToken<any>,
IClass extends Constructor<ProviderInstanceType<AClass>>,
DClass extends MapParametersToDeps<ConstructorParameters<IClass>>,
// types for useValue
AValue extends SafeInjectionToken<any>,
VValue extends SafeInjectionTokenType<AValue>,
// types for useFactoryWithToken
AFactoryToken extends SafeInjectionToken<any>,
IFactoryToken extends (...args: any) => InstanceType<SafeInjectionTokenType<AFactoryToken>>,
DFactoryToken extends MapParametersToDeps<Parameters<IFactoryToken>>,
// types for useFactoryWithClass
AFactoryClass extends AbstractConstructor<any>,
IFactoryClass extends (...args: any) => InstanceType<AFactoryClass>,
DFactoryClass extends MapParametersToDeps<Parameters<IFactoryClass>>,
// types for useFactory
AFactory extends AbstractConstructor<any> | SafeInjectionToken<any>,
IFactory extends (...args: any) => ProviderInstanceType<AFactory>,
DFactory extends MapParametersToDeps<Parameters<IFactory>>,
// types for useExisting
AExisting extends Constructor<any> | AbstractConstructor<any>,
AExisting extends Constructor<any> | AbstractConstructor<any> | SafeInjectionToken<any>,
IExisting extends
| Constructor<InstanceType<AExisting>>
| AbstractConstructor<InstanceType<AExisting>>,
| Constructor<ProviderInstanceType<AExisting>>
| AbstractConstructor<ProviderInstanceType<AExisting>>,
>(
provider:
| SafeClassProvider<AClass, IClass, DClass>
| SafeValueProvider<AValue, VValue>
| SafeFactoryProviderWithToken<AFactoryToken, IFactoryToken, DFactoryToken>
| SafeFactoryProviderWithClass<AFactoryClass, IFactoryClass, DFactoryClass>
| SafeFactoryProvider<AFactory, IFactory, DFactory>
| SafeExistingProvider<AExisting, IExisting>
| Constructor<unknown>,
): SafeProvider => provider as SafeProvider;

View File

@@ -1,5 +1,4 @@
import { LOCALE_ID, NgModule } from "@angular/core";
import { UnwrapOpaque } from "type-fest";
import {
AuthRequestServiceAbstraction,
@@ -267,7 +266,7 @@ import { ModalService } from "./modal.service";
* Add your provider definition here using the safeProvider function as a wrapper. This will give you type safety.
* If you need help please ask for it, do NOT change the type of this array.
*/
const typesafeProviders: Array<SafeProvider> = [
const safeProviders: SafeProvider[] = [
safeProvider(AuthGuard),
safeProvider(UnauthGuard),
safeProvider(ModalService),
@@ -1085,6 +1084,6 @@ function encryptServiceFactory(
@NgModule({
declarations: [],
// Do not register your dependency here! Add it to the typesafeProviders array using the helper function
providers: typesafeProviders as UnwrapOpaque<SafeProvider>[],
providers: safeProviders,
})
export class JslibServicesModule {}