Disclaimer: This
README.mdfile was generated by an LLM (Large Language Model).
This project provides a foundational implementation of Domain-Driven Design (DDD) Value Objects in TypeScript, tailored for Node.js applications. It demonstrates how to create immutable value objects that encapsulate data, ensure data integrity through validation, and provide value-based equality comparisons.
The primary goal is to illustrate best practices for designing robust and maintainable domain models using Value Objects, focusing on concepts like immutability, self-validation, and proper equality semantics.
Value Objects are objects that measure, quantify, or describe a thing in the domain. They are characterized by:
- Immutability: Once created, their state cannot change.
- Value-Based Equality: Two value objects are considered equal if all their constituent attributes are equal, not by their memory reference.
- Self-Validation: They enforce their own invariants upon creation.
- No Side Effects: Operations on value objects return new instances rather than modifying the original.
The src/domain/abstractions/value-object.abstract.ts file defines an abstract ValueObject class. This class serves as the base for all concrete value objects in the system, providing:
- A generic
equals(other: ValueObject)method that performs deep value-based comparison. - An abstract
getEqualityComponents(): any[]method, which concrete subclasses must implement to specify the properties that define their unique value for comparison.
The project includes several examples of practical value objects:
- Represents an email address.
- Validates the email format and normalizes it (e.g., converts to lowercase).
- Demonstrates basic string-based value object principles.
- Represents a monetary amount.
- Utilizes
bignumber.jsto handle precise decimal arithmetic, avoiding common floating-point inaccuracies. - Enforces non-negative values.
- Provides methods for arithmetic operations like
add()andtimes().
- Represents a currency code (e.g., "USD", "EUR").
- Ensures that only predefined, supported currency codes can be used.
- Provides static factory methods (
fromCode) and predefined instances (Currency.None,Currency.All).
- A composite value object combining
AmountandCurrency. - Demonstrates how to compose smaller value objects into more complex ones.
- Includes business logic, such as ensuring that
add()operations are only performed betweenMoneyobjects of the same currency. - Provides static factory methods, including
zero()for creating zero-value money instances.
├───src/
│ ├───app.ts # Example usage and demonstration of value objects
│ └───domain/
│ ├───abstractions/
│ │ └───value-object.abstract.ts # Base class for all Value Objects
│ ├───types/
│ │ └───currency.type.ts # Defines available currency codes
│ ├───amount.vo.ts # Value Object for monetary amounts
│ ├───currency.vo.ts # Value Object for currency codes
│ ├───email.vo.ts # Value Object for email addresses
│ └───money.vo.ts # Composite Value Object for money (Amount + Currency)
├───package.json # Project dependencies and scripts
├───tsconfig.json # TypeScript configuration
├───biome.json # Biome configuration for linting and formatting
├───.gemini.md # Context for the Gemini AI assistant
└───... # Other configuration and development files
This project uses Structurizr to create diagrams based on the C4 model. The diagrams are defined as code in the architecture/workspace.dsl file.
You can explore the diagrams locally using Structurizr Lite, which can be run with Docker.
-
Start the Structurizr Lite container:
docker-compose up
-
Access the diagrams: Open your web browser and navigate to
http://localhost:8081.
The docker-compose.yml file is configured to mount the local ./architecture directory into the container, so any changes you make to the .dsl file will be reflected in the Structurizr Lite web interface.
Note: The diagrams below are SVG exports of the architecture. For the most up-to-date and interactive versions, please run Structurizr Lite locally.
The following diagrams are defined in the workspace:
-
Domain-Layer-Overview: This component diagram shows all the value objects within the "Domain Layer" container and their relationships to each other and to the abstract
ValueObjectbase class. It provides a high-level view of the entire value object system. -
Email-Value-Object: A focused component diagram showing only the
Emailvalue object and its inheritance from theValueObjectbase class. This is useful for understanding a single, simple value object in isolation. -
Money-Value-Object: A more detailed component diagram that illustrates the composite
Moneyvalue object. It shows howMoneyis composed of theAmountandCurrencyvalue objects, their inheritance structure, and the external dependency on thebignumber.jslibrary.
- TypeScript: For type safety and better code organization.
- Node.js: The JavaScript runtime environment.
- pnpm: A fast, disk space efficient package manager.
- bignumber.js: A JavaScript library for arbitrary-precision decimal and non-decimal arithmetic.
- tsx: A TypeScript execution environment for Node.js, enabling direct execution of TypeScript files.
- Biome: A fast formatter and linter for web projects.
To set up the project and run the examples:
- Node.js (v18 or higher recommended)
- pnpm (install globally:
npm install -g pnpm)
-
Clone the repository:
git clone https://github.com/your-username/nodejs-ddd-value-objects.git cd nodejs-ddd-value-objects -
Install dependencies:
pnpm install
The app.ts file contains various examples demonstrating the usage of the implemented value objects.
To run the examples:
pnpm devThis command will run src/app.ts in watch mode, automatically restarting if you make changes.
To run the compiled version:
pnpm startTo compile the TypeScript code into JavaScript:
pnpm buildThis will output compiled JavaScript files into the dist directory.
This project uses Biome for linting and formatting. To check for linting and formatting issues:
pnpm biome check .To fix linting and formatting issues automatically:
pnpm biome format --write .(Note: The actual biome commands might be slightly different based on package.json scripts, but these are general examples.)
This project is licensed under the MIT License. See the LICENSE file for more details.