Scalar Modules Overview

Scalar modules provide reusable value objects for embedded documents, shared DTOs, and internationalized data structures across your application. Think of Scalars as reusable Lego pieces - small, focused data structures that can be combined into larger models.
Unlike full Models that have their own database collections, Scalars are embedded within other models. They are perfect for:
  • Embedded documents in domain models (e.g., address, contact info)
  • Shared DTOs and configuration objects across modules
  • Type-safe schemas with runtime validation
  • Internationalized data structures with full i18n support

Core Principles

🔄Reusability
Designed for cross-module consumption. Define once, use everywhere.
📦Stateless
Pure data containers without business logic. Focus on structure, not behavior.
🛡️Type-Safe
Full TypeScript integration with runtime validation through field options.
🧩Composable
Embeddable within larger domain models. Scalars can contain other scalars.

File Structure

Scalar modules are stored in the special __scalar directory within your library. Each scalar has its own directory with three key files:
*.constant.ts

Defines the scalar schema using via() function and enums using enumOf(). This is where you declare fields, types, defaults, and validation rules.

*.dictionary.ts

Provides internationalization using scalarDictionary() builder pattern. Defines translations for model name, field labels, descriptions, and enum values.

*.document.ts

Optional file that extends functionality using by() function. Add custom methods for data transformations and computed values.

Defining Scalars

Akan.js uses a functional approach to define scalars. The via() function creates type-safe schema definitions, while enumOf() creates typed enum classes. Here's a real example from the framework:
price.constant.ts
Let's understand the key patterns:
enumOf(name, values)

Creates a typed enum class. The first argument is the enum name (used in dictionary), the second is an array of values with "as const" for type safety.

via((field) => ({...}))

Creates a scalar class with typed fields. The field() function accepts a type and optional configuration for defaults, validation, and more.

Field Options

Options include: default (static or function), min/max (for numbers), minlength/maxlength (for strings), validate (custom validator function).

scalarDictionary()

The scalarDictionary() function provides a fluent builder pattern for defining translations. It ensures type safety and complete coverage of all fields and enum values.
price.dictionary.ts
Let's understand the dictionary builder pattern:
scalarDictionary([languages])

Initialize with supported languages array. The order determines which index corresponds to which language in translation arrays.

.of((t) => ...)

Define the scalar's own name and description. Use t([en, ko]) for the label and .desc([en, ko]) for the description.

.model<Type>((t) => ({...}))

Define translations for each field. The generic type ensures all fields are covered. Each field has a label and description.

.enum<Type>(name, (t) => ({...}))

Define translations for enum values. The first argument is the enum name (matching enumOf()), the second defines translations for each value.

Document Extensions with by()

The document file extends your scalar with custom methods using the by() function. This is optional but useful for adding computed properties and data transformation methods.
price.document.ts
Key points about document extensions:
by(cnst.ClassName)

Wraps the constant class and enables adding methods. Import the constant as cnst to avoid naming conflicts.

Custom Methods

Add computed properties, validation helpers, and transformation methods directly in the class body.

Access Fields

Use 'this' to access all fields defined in the constant file. TypeScript provides full autocompletion.

Naming Conventions

Consistent naming is crucial for maintainability. Follow these conventions:
Scalar Directory

camelCase (e.g., encourageInfo)

Constant File

[name].constant.ts (e.g., encourageInfo.constant.ts)

Dictionary File

[name].dictionary.ts (e.g., encourageInfo.dictionary.ts)

Document File

[name].document.ts (e.g., encourageInfo.document.ts)

Scalar Class

PascalCase (e.g., EncourageInfo)

Enum Class

PascalCase (e.g., Journey, LinkType)

Enum Values

camelCase (e.g., firstJoin, waitPay)

Best Practices

Design for Reusability

Create scalars that can be used across multiple modules. Think about common data patterns like addresses, contact info, or status tracking.

Keep Scalars Focused

Each scalar should represent a single concept. If a scalar grows too large, consider splitting it into smaller, composable pieces.

Use Proper Defaults

Provide sensible defaults for optional fields. Use function defaults (e.g., () => dayjs()) for dynamic values that should be computed at creation time.

Complete Dictionary Coverage

Always provide translations for all fields and enum values. Use the type system to ensure nothing is missed.

Validate at Field Level

Use field options like min/max, minlength/maxlength, and custom validate functions to ensure data integrity at the schema level.

Integration Points

Scalars integrate seamlessly with other parts of the Akan.js framework:
Domain Models

Embed scalars in models using field([ScalarClass])

GraphQL

Auto-generated types and enums for API contracts

Validation

Runtime type checking through field options

Internationalization

Consistent terminology via scalarDictionary()

UI Components

Enum values can be directly used in select fields

Dictionary Sharing

Reuse enum translations across dictionaries

🎉 What You've Learned:
  • How to create scalars using via() and enumOf() functions
  • How to define internationalization with scalarDictionary()
  • How to extend scalars with custom methods using by()
  • Naming conventions and best practices for scalars
  • How scalars integrate with models and other framework features
Check out the Tutorials section for hands-on examples of creating and using scalars in real applications.
Released under the MIT License
Official Akan.js Consulting onAkansoft
Copyright © 2025 Akan.js. All rights reserved.
System managed bybassman