functional-ts
Functional Domain Modeling in TypeScript
Principles for writing domain models in server-side TypeScript. Instead of class-based OOP, this approach maximizes the TypeScript type system through a functional style.
1. Type-Driven Domain Modeling
Represent states with discriminated unions using kind as the unified discriminant. Use type (not interface), companion objects, branded types, Readonly<>, function property notation, and one-concept-per-file structure.
Validation library detection: Check dependencies / devDependencies in the project's package.json for branded type syntax:
zod→ validation-libraries/zod.mdvalibot→ validation-libraries/valibot.mdarktype→ validation-libraries/arktype.md
Details: domain-modeling.md
2. State Transitions via Functions
Express state transitions with pure functions. The argument type constrains valid source states, and the return type makes the target state explicit. Invalid transitions become compile errors. Use assertNever for exhaustiveness checking.
Details: state-modeling.md
3. Error Handling — Railway Oriented Programming
Do not throw exceptions; treat errors as values using the Result type. Define error types as discriminated unions so callers can handle them exhaustively.
Library detection: Check dependencies / devDependencies in the project's package.json:
neverthrow→ result-libraries/neverthrow.mdbyethrow→ result-libraries/byethrow.mdfp-ts→ result-libraries/fp-ts.mdoption-t→ result-libraries/option-t.md
Details: error-handling.md
4. Boundary Defense
Validate external inputs (API requests, DB results, file reads) with validation library schemas at runtime. Trust types inside the domain layer. Do not use type assertions (as). Apply Sensitive<T> wrapper to PII fields.
Details: boundary-defense.md
5. Declarative Style
Write array transformations declaratively using filter / map / reduce with companion object predicates. Model domain events as immutable records.
Details: declarative-style.md
6. Test Data
Define test data with as const satisfies Type to preserve discriminant literal types and prevent widening.
Details: test-data.md
Applying These Principles
These are recommendations, not strict rules. You may use your judgment based on context, but if you deviate from a principle, explicitly state the reason in a comment.
Typical justified reasons to deviate:
- An external library requires class inheritance
- Immutable object creation cost is a performance concern
- A different pattern has been adopted by team agreement
More from iwasa-kosui/functional-ts-principles
functional-ts-review
Use when reviewing TypeScript server-side code for adherence to functional domain modeling principles. Checks the same principles enforced by the `functional-ts` skill — discriminated unions, companion objects, branded types, immutability, file structure, pure state transitions, exhaustiveness, Result-based error handling, boundary defense (schema validation, no `as`, PII protection), declarative style, and type-safe test data.
17functional-ts-ja
サーバーサイドTypeScriptでドメインモデル、ユースケース、リポジトリ、状態遷移、ビジネスロジックを書くときに使用する。Discriminated Union、純粋関数、Result型による関数型ドメインモデリングをガイドする。
10functional-ts-review-ja
サーバーサイドTypeScriptコードを関数型ドメインモデリング原則に照らしてレビューする。`functional-ts-ja` スキルと同じナレッジを参照し、Discriminated Union、Companion Object、Branded Types、不変性、ファイル構成、純粋関数による状態遷移、網羅性チェック、Result型によるエラーハンドリング、境界の防御(スキーマバリデーション・`as` 禁止・PII 保護)、宣言的スタイル、型安全なテストデータをチェックする。
9