Guides
Identifier

Identifier

There are two ways to create an identifier.

Class as identifier

A class could be the identifier of iteself:

class ClassDependency {}
 
const injector = new Injector([[ClassDependency]])

So you can get the dependency from the injector directly:

const classDependency = injector.get(ClassDependency)

However, this approach leave abstraction aside and hence is less flexible.

IdentifierDecorator

The recommended way is to create an identifier with IdentifierDecorator, which allows a module to depend on an interface instead of a concrete class.

For example, our code needs to depend on a clipboard service to read data from the system clipboard. We can create an interface IClipboardInterfaceService and its corresponding identifier:

export interface IClipboardInterfaceService{
  readText(): string | undefined;
}
 
export const IClipboardInterfaceService = createIdentifier<IClipboardInterfaceService>('clipboard-interface');
💡
In TypeScript, type variables and value variables are in different namespaces, so it is legal to have an interface and a value with the same name IClipboardInterfaceService. This trick can combine the interface and the identifier, reducing the developer's cognitive burden.

Then when providing the dependency corresponding to this interface, we can inject different classes in different runtime environments. For example, we can inject an implementation for the native browser API in the browser:

class WebClipboardInterfaceService implements IClipboardInterfaceService {
  readText() {
    return navigator.clipboard.readText();
  }
}
 
const injector = new Injector([[IClipboardInterface, { useClass: WebClipboardInterfaceService }]])

And use a bridge to implement in the mobile environment:

class MobileClipboardInterfaceService implements IClipboardInterfaceService {
  readText() {
    return bridge.readText();
  }
}
 
const injector = new Injector([[IClipboardInterface, { useClass: MobileClipboardInterfaceService }]])

Then you can get the dependency by the identifier:

const clipboardService = injector.get(IClipboardInterfaceService)
💡
If your application supports multiple environments, you probably have different bundles for each environment. Please make sure that you only include the implementation that is needed in that bundle.

This way, you can easily switch the implementation of the clipboard service in different environments without changing the code that uses the service.