Release v7.12.0
Summary
Implements TypeScript/JavaScript equivalent of C# ConceptAs<T> for strongly-typed domain identifiers and value objects. Enables type-safe wrappers around primitives (string, number, boolean) with automatic JSON serialization and union type support for flexible assignment.
The recommended pattern exports union types from the concept file for convenience and ease of reading:
// UserId.ts
import { ConceptAs } from '@cratis/fundamentals';
class UserIdConcept extends ConceptAs<string> {}
export type UserId = UserIdConcept | string;
// OrderCount.ts
class OrderCountConcept extends ConceptAs<number> {}
export type OrderCount = OrderCountConcept | number;
// Order.ts
class Order {
// @field takes the concept class, type annotation uses the exported union type
@field(UserIdConcept) userId!: UserId;
@field(OrderCountConcept) count!: OrderCount;
}
const order = new Order();
// Can assign concept instances
order.userId = new UserIdConcept('user-123');
order.count = new OrderCountConcept(42);
// Or assign primitives directly
order.userId = 'user-456';
order.count = 99;
// Both serialize to primitive values: {"userId":"user-456","count":99}
const json = JsonSerializer.serialize(order);
// Always deserializes to typed concept instances
const restored = JsonSerializer.deserialize(Order, json);
console.log(restored.userId instanceof UserIdConcept); // trueAdded
- ConceptAs abstract class with value property, valueOf(), and toString() methods
- Union type support with recommended export pattern: concept class with "Concept" suffix and clean union type export (e.g.,
class UserIdConcept→export type UserId = UserIdConcept | string) - Flexible assignment of both ConceptAs instances and primitives through exported union types
- Recursive serialization pattern following C# implementation (recognize ConceptAs → unwrap → serialize inner value)
- Prototype chain-based type detection in JsonSerializer for ConceptAs subclasses
- 216 comprehensive tests covering creation, serialization, deserialization, and union type scenarios
- Complete documentation at Documentation/typescript/concept_as.md with union type export pattern, examples, and best practices
- Comparison table highlighting differences between C# and TypeScript implementations
Changed
- JsonSerializer now follows C# pattern: recognizes ConceptAs types, unwraps to inner value, then recursively serializes using reliable type detection
- JsonSerializer serializes both ConceptAs instances and primitives to inner values and deserializes JSON primitives back to ConceptAs instances based on @field decorator
- Updated TypeScript documentation index and table of contents to include ConceptAs
- Reorganized test structure: moved serialization tests from
for_ConceptAstofor_JsonSerializerto reflect that serialization is a JsonSerializer concern, while keeping ConceptAs creation tests self-contained