Typescript Dependency Contracts for dependency inversion
- Project documentation
- License
- Contributing
- Code of conduct
- Coding standards
- Security policy
- Pull request template
- How to use API
- Test coverage report
npm install @jonloucks/contracts-tsv2.0.0 introduces a smaller root export surface, removes deprecated APIs, and finalizes ESM packaging.
Root package imports are intentionally minimal
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";Transform types moved out of api/Types
// 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";Functional barrel removed
// 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";Importing the Package
import { CONTRACTS, createContract } from '@jonloucks/contracts-ts';Importing the Convenience Package
import {
type AutoClose,
bind,
claim,
type Contract,
createExtractor,
createLifeCycle,
createRepository,
createSingleton,
createValue,
createContract,
enforce,
guardFunctions,
isBound
} from "@jonloucks/contracts-ts/api/Convenience";Creating a Contract
// 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
}
});Binding a Contract
bind<Logger>(LOGGER_CONTRACT,
createSingleton<Logger>(
() => ({
log: (message: string) => {
console.log("LOG:", message);
}
})));Using the Contract
const logger : Logger = enforce<Logger>(LOGGER_CONTRACT);
logger.log("Using the service in the test.");Install dependencies
npm installBuild the project
npm run buildRun tests
npm testRun tests in watch mode
npm run test:watchRun test coverage
npm run test:coverageLint the code
npm run lintFix linting issues
npm run lint:fixGenerate documents
npm run docsGenerate badges
npm run badgesProject Structure
- All tests must have suffix of -test.ts or -spec.ts
- Tests that validate supported APIs go in src/test
- Tests that validate internal implementation details go in src/impl
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
CI Workflow
The CI workflow runs on every push and pull request to main branch. It:
- Tests against supported Node.js versions
20.19.0+,22.13.0+, and24.x - Runs linting
- Builds the project
- Runs tests with coverage
- Uploads coverage to Codecov (optional)
Compatibility note:
- Production
AutoCloseimplementations intentionally support bothSymbol.disposeandSymbol.for("Symbol.dispose")keys, so disposal remains stable in environments that do not provideSymbol.dispose.
Publish Workflow
The GitHub publishings workflows are run to make an official release.
- If all scanning and tests pass it is published. There is no other way allowed.
- Publishing authentication is done using (OIDC trusted publishing)
To set up your own publishing:
- Publishing this project as is intentionally disabled
- You are welcome to fork this repository and publish where you want.
- Run
npm pkg delete privateto remove theprivateflag from the package. - Change the
namefield inpackage.jsonto your desired package name.
MIT