Typescript Dependency Contracts for dependency inversion
npm install @jonloucks/contracts-ts
v2.0.0 introduces a smaller root export surface, removes deprecated APIs, and finalizes ESM packaging.
Use root imports only for core exports:
import {
CONTRACTS,
Contract,
ContractConfig,
ContractException,
Contracts,
ContractsConfig,
createContract,
createContracts,
VERSION
} from "@jonloucks/contracts-ts";
For broader helper APIs, use convenience or explicit subpath imports:
import { bind, enforce, createSingleton } from "@jonloucks/contracts-ts/api/Convenience";
import { createAtomicBoolean } from "@jonloucks/contracts-ts/auxiliary/Convenience";
// v1.x (removed)
// import { TransformType, typeToTransform } from "@jonloucks/contracts-ts/api/Types";
// v2.0.0
import { type Type as TransformType } from "@jonloucks/contracts-ts/auxiliary/Transform";
// v1.x (removed)
// import { TransformType } from "@jonloucks/contracts-ts/auxiliary/Functional";
// v2.0.0
import {
type TransformType,
transformFromType,
transformGuard
} from "@jonloucks/contracts-ts/auxiliary/Convenience";
import { CONTRACTS, createContract } from '@jonloucks/contracts-ts';
import {
type AutoClose,
bind,
claim,
type Contract,
createExtractor,
createLifeCycle,
createRepository,
createSingleton,
createValue,
createContract,
enforce,
guardFunctions,
isBound
} from "@jonloucks/contracts-ts/api/Convenience";
// Define a service interface
interface Logger {
log(message: string): void;
}
// Create a contract for the service
const LOGGER_CONTRACT: Contract<Logger> = createContract<Logger>({
name: "Logger",
test: (obj: unknown): obj is Logger => { // example of duck-typing check
return guardFunctions(obj, 'log'); // example of using guardFunctions helper
}
});
bind<Logger>(LOGGER_CONTRACT,
createSingleton<Logger>(
() => ({
log: (message: string) => {
console.log("LOG:", message);
}
})));
const logger : Logger = enforce<Logger>(LOGGER_CONTRACT);
logger.log("Using the service in the test.");
npm install
npm run build
npm test
npm run test:watch
npm run test:coverage
npm run lint
npm run lint:fix
npm run docs
npm run badges
contracts-ts
├── .github
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows
│ ├── main-pull-request-matrix.yml
│ ├── main-pull-request.yml
│ ├── main-push.yml
│ └── main-release.yml
├── CODE_OF_CONDUCT.md
├── CODING_STANDARDS.md
├── CONTRIBUTING.md
├── DOCUMENTATION.md
├── .editorconfig
├── eslint.config.mjs
├── LICENSE
├── package-lock.json
├── package.json
├── PULL_REQUEST_TEMPLATE.md
├── README.md
├── SECURITY.md
├── src
│ ├── index.ts
│ ├── version.ts
│ ├── api
│ │ └── *.ts
│ ├── auxiliary
│ │ └── *.ts
│ ├── impl
│ │ ├── *.ts
│ │ └── *.test.ts // internal implementation specific
│ ├── test
│ │ └── *.test.ts
│ └── never-publish // non shippable development scripts (if present)
├── tsconfig.json
└── typedoc.json
The CI workflow runs on every push and pull request to main branch. It:
20.19.0+, 22.13.0+, and 24.xCompatibility note:
AutoClose implementations intentionally support both Symbol.dispose and Symbol.for("Symbol.dispose") keys, so disposal remains stable in environments that do not provide Symbol.dispose.The GitHub publishings workflows are run to make an official release.
To set up your own publishing:
npm pkg delete private to remove the private flag from the package.name field in package.json to your desired package name.MIT