Dependencies
November 8, 2020 ยท View on GitHub
Functions are created using a variant of Dependency Injection.
Any method with dependencies that should be stubbed out during tests, such as file system bindings, logging, or other functions,
takes in a first argument of name dependencies.
Its dependencies object is manually created in src/cli/main.ts and bound to the method with bind.
When to Use Dependencies
Most functions don't need a dependencies object.
Only add one if something should be stubbed out during tests or should be available to multiple callers.
How to Use Dependencies
Suppose your method myMethod, should take in a fileSystem, a string, and a number:
-
Create a
MyMethodDependenciestype inmyMethod.ts:// ~~~/myMethod.ts export type MyMethodDependencies = { fileSystem: FileSystem; }; -
Add
dependencies: MyMethodDependenciesas the first argument tomyMethod:// ~~~/myMethod.ts export const myMethod = async ( dependencies: MyMethodDependencies, argumentOne: string, argumentTwo: number, ) => { // ... }; -
In
src/cli/main.ts, create amyMethodDependencies: MyMethodDependencies:// src/cli/main.ts const myMethodDependencies: MyMethodDependencies = { fileSystem, }; -
In
src/cli/main.ts, includemyMethod: bind(mymethod, myMethodDependencies)in any dependencies object that requiresmyMethod:// src/cli/main.ts const otherMethodDependencies: OtherMethodDependencies = { myMethod: bind(myMethod, myMethodDependencies), }; -
In the types of any dependencies that include
myMethod, addmyMethod: SansDependencies<typeof myMethod>to require the result ofbindingmyMethod:// ~~~/otherMethod.ts export type OtherMethodDependencies = { myMethod: SansDependencies<typeof myMethod>; };
Adapters
Global Node constructs as console are never written to directly by functions; instead, "adapter" wrappers are set up in src/adapters/*.ts and provided as dependencies to functions.
This enables native calls to be directly tested in tests without stubbing out their global equivalents.