moleculeInterface
Sometimes you don’t care about the implementation details. Your molecules need a dependency, but it doesn’t matter where it comes from or how it’s implemented. Bunshi supports interfaces as a tool to fix this problem.
An interface defines a dependency, but not the implementation for the dependency or how it gets created.
API
In other programming languages interfaces can be referenced at build time or runtime, but Javascript doesn’t have interfaces and Typescript interfaces don’t exist at runtime.
Bunshi has moleculeInterface to create molecule interfaces that can be referenced and used at runtime.
import { moleculeInterface } from "bunshi";
export interface SendsEmail {
sendEmail(recipient: string);
}
export const SendsEmailMolecule = moleculeInterface<SendsEmail>();
Molecules can depend on interfaces, not just other molecules.
import { molecule } from "bunshi";
import { SendsEmailMolecule } from "./molecules";
import { FormMolecule } from "./forms";
export const RegistrationFormMolecule = molecule((mol) => {
const emailSender = mol(SendsEmailMolecule);
const form = mol(FormMolecule);
const onSubmit = () => {
emailSender.sendEmail(form.getData().email);
};
return {
form,
onSubmit,
};
});
Usage with Injectors
Interfaces are resolved through injectors with interface bindings. Child injectors can inherit bindings from parent injectors.
Basic Binding
const injector = createInjector({
bindings: [[ApiClientInterface, FetchApiClientMolecule]]
});
const apiClient = injector.get(ApiClientInterface);
Parent-Child Hierarchy
const parentInjector = createInjector({
bindings: [[ApiClientInterface, ProductionApiClientMolecule]]
});
const childInjector = createInjector({
parent: parentInjector,
bindings: [[CacheInterface, MemoryCacheMolecule]]
});
// Child can access both ApiClientInterface (from parent) and CacheInterface (local)
Testing & Environment Configuration
// Override parent bindings for testing
const testInjector = createInjector({
parent: productionInjector,
bindings: [[ApiClientInterface, MockApiClientMolecule]]
});
// Environment-specific injectors
const injector = isDev ? devInjector : prodInjector;
Tips
- Interfaces don’t specify if they are scoped or not. Write your molecules accordingly.
- Bindings to interfaces have to be done in injectors using the
bindingsparameter. - Use parent injectors to create hierarchical configurations where child injectors inherit base bindings.
- Child injectors can override parent bindings by providing their own implementation for the same interface.
- Interfaces can be provided in React applications using MoleculeProvider.
- If you have a default implementation for an interface, then just use a
moleculeinstead. - Scopes can act as a replacement for interfaces if you have a large number of implementations