{"id":"41ed76a6-d2e7-48a1-83ff-4fe37008c96d","shortId":"BHvLSm","kind":"skill","title":"functional-ts","tagline":"Use when writing server-side TypeScript code involving domain models, use cases, repositories, state transitions, or business logic. Guides functional domain modeling with discriminated unions, pure functions, and Result types.","description":"# Functional Domain Modeling in TypeScript\n\nPrinciples for writing domain models in server-side TypeScript. Instead of class-based OOP, this approach maximizes the TypeScript type system through a functional style.\n\n## 1. Type-Driven Domain Modeling\n\nRepresent 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.\n\n**Validation library detection:** Check `dependencies` / `devDependencies` in the project's `package.json` for branded type syntax:\n\n- `zod` → [validation-libraries/zod.md](./validation-libraries/zod.md)\n- `valibot` → [validation-libraries/valibot.md](./validation-libraries/valibot.md)\n- `arktype` → [validation-libraries/arktype.md](./validation-libraries/arktype.md)\n\nDetails: [domain-modeling.md](./domain-modeling.md)\n\n## 2. State Transitions via Functions\n\nExpress 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.\n\nDetails: [state-modeling.md](./state-modeling.md)\n\n## 3. Error Handling — Railway Oriented Programming\n\nDo not throw exceptions; treat errors as values using the Result type. Define error types as discriminated unions so callers can handle them exhaustively.\n\n**Library detection:** Check `dependencies` / `devDependencies` in the project's `package.json`:\n\n- `neverthrow` → [result-libraries/neverthrow.md](./result-libraries/neverthrow.md)\n- `byethrow` → [result-libraries/byethrow.md](./result-libraries/byethrow.md)\n- `fp-ts` → [result-libraries/fp-ts.md](./result-libraries/fp-ts.md)\n- `option-t` → [result-libraries/option-t.md](./result-libraries/option-t.md)\n\nDetails: [error-handling.md](./error-handling.md)\n\n## 4. Boundary Defense\n\nValidate 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.\n\nDetails: [boundary-defense.md](./boundary-defense.md)\n\n## 5. Declarative Style\n\nWrite array transformations declaratively using `filter` / `map` / `reduce` with companion object predicates. Model domain events as immutable records.\n\nDetails: [declarative-style.md](./declarative-style.md)\n\n## 6. Test Data\n\nDefine test data with `as const satisfies Type` to preserve discriminant literal types and prevent widening.\n\nDetails: [test-data.md](./test-data.md)\n\n## Applying These Principles\n\nThese 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.\n\nTypical justified reasons to deviate:\n- An external library requires class inheritance\n- Immutable object creation cost is a performance concern\n- A different pattern has been adopted by team agreement","tags":["functional","principles","iwasa-kosui","agent-skills"],"capabilities":["skill","source-iwasa-kosui","skill-functional-ts","topic-agent-skills"],"categories":["functional-ts-principles"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/iwasa-kosui/functional-ts-principles/functional-ts","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add iwasa-kosui/functional-ts-principles","source_repo":"https://github.com/iwasa-kosui/functional-ts-principles","install_from":"skills.sh"}},"qualityScore":"0.458","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 17 github stars · SKILL.md body (3,009 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-10T07:03:40.131Z","embedding":null,"createdAt":"2026-05-10T07:03:40.131Z","updatedAt":"2026-05-10T07:03:40.131Z","lastSeenAt":"2026-05-10T07:03:40.131Z","tsv":"'/arktype.md':134 '/boundary-defense.md':288 '/byethrow.md':229 '/declarative-style.md':312 '/domain-modeling.md':138 '/error-handling.md':249 '/fp-ts.md':237 '/neverthrow.md':223 '/option-t.md':245 '/result-libraries/byethrow.md':230 '/result-libraries/fp-ts.md':238 '/result-libraries/neverthrow.md':224 '/result-libraries/option-t.md':246 '/state-modeling.md':178 '/test-data.md':334 '/valibot.md':128 '/validation-libraries/arktype.md':135 '/validation-libraries/valibot.md':129 '/validation-libraries/zod.md':123 '/zod.md':122 '1':67 '2':139 '3':179 '4':250 '5':289 '6':313 'adopt':390 'agreement':393 'api':256 'appli':280,335 'approach':57 'argument':151 'arktyp':130 'array':293 'assert':278 'assertnev':172 'base':54,349 'becom':168 'boundari':251 'boundary-defense.md':287 'brand':90,115 'busi':21 'byethrow':225 'caller':204 'case':16 'check':106,175,211 'class':53,375 'class-bas':52 'code':11 'comment':365 'companion':88,301 'compil':169 'concept':99 'concern':384 'const':321 'constrain':153 'context':351 'cost':380 'creation':379 'data':315,318 'db':258 'declar':290,295 'declarative-style.md':311 'defens':252 'defin':197,316 'depend':107,212 'detail':136,176,247,286,310,332 'detect':105,210 'devdepend':108,213 'deviat':355,370 'differ':386 'discrimin':28,76,83,201,326 'domain':13,25,36,43,71,272,305 'domain-modeling.md':137 'driven':70 'error':170,180,190,198 'error-handling.md':248 'event':306 'except':188 'exhaust':174,208 'explicit':165,359 'express':144 'extern':254,372 'field':285 'file':101,260 'filter':297 'fp':232 'fp-ts':231 'function':2,24,31,35,65,93,143,149 'functional-t':1 'guid':23 'handl':181,206 'immut':308,377 'inherit':376 'input':255 'insid':270 'instead':50 'interfac':87 'invalid':166 'involv':12 'judgment':348 'justifi':367 'kind':79 'layer':273 'librari':104,121,127,133,209,222,228,236,244,264,373 'liter':327 'logic':22 'make':161 'map':298 'maxim':58 'may':345 'model':14,26,37,44,72,304 'neverthrow':219 'notat':95 'object':89,302,378 'one':98 'one-concept-per-fil':97 'oop':55 'option':240 'option-t':239 'orient':183 'package.json':113,218 'pattern':387 'per':100 'perform':383 'pii':284 'predic':303 'preserv':325 'prevent':330 'principl':40,337,358 'program':184 'project':111,216 'properti':94 'pure':30,148 'railway':182 'read':261 'readon':92 'reason':362,368 'recommend':340 'record':309 'reduc':299 'repositori':17 'repres':73 'request':257 'requir':374 'result':33,195,221,227,235,243,259 'result-librari':220,226,234,242 'return':159 'rule':343 'runtim':267 'satisfi':322 'schema':265 'sensit':281 'server':8,47 'server-sid':7,46 'side':9,48 'skill' 'skill-functional-ts' 'sourc':155 'source-iwasa-kosui' 'state':18,74,140,145,156,164,360 'state-modeling.md':177 'strict':342 'structur':102 'style':66,291 'syntax':117 'system':62 'target':163 'team':392 'test':314,317 'test-data.md':333 'throw':187 'topic-agent-skills' 'transform':294 'transit':19,141,146,167 'treat':189 'trust':268 'ts':3,233 'type':34,61,69,85,91,116,152,160,196,199,269,277,323,328 'type-driven':68 'typescript':10,39,49,60 'typic':366 'unifi':82 'union':29,77,202 'use':4,15,78,84,171,193,276,296,346 'valibot':124 'valid':103,120,126,132,154,253,263 'validation-librari':119,125,131 'valu':192 'via':142 'widen':331 'wrapper':282 'write':6,42,292 'zod':118","prices":[{"id":"ba5f7844-58fb-49da-b0e2-06d1522438d1","listingId":"41ed76a6-d2e7-48a1-83ff-4fe37008c96d","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"iwasa-kosui","category":"functional-ts-principles","install_from":"skills.sh"},"createdAt":"2026-05-10T07:03:40.131Z"}],"sources":[{"listingId":"41ed76a6-d2e7-48a1-83ff-4fe37008c96d","source":"github","sourceId":"iwasa-kosui/functional-ts-principles/functional-ts","sourceUrl":"https://github.com/iwasa-kosui/functional-ts-principles/tree/main/skills/functional-ts","isPrimary":false,"firstSeenAt":"2026-05-10T07:03:40.131Z","lastSeenAt":"2026-05-10T07:03:40.131Z"}],"details":{"listingId":"41ed76a6-d2e7-48a1-83ff-4fe37008c96d","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"iwasa-kosui","slug":"functional-ts","github":{"repo":"iwasa-kosui/functional-ts-principles","stars":17,"topics":["agent-skills"],"license":"mit","html_url":"https://github.com/iwasa-kosui/functional-ts-principles","pushed_at":"2026-05-10T07:01:36Z","description":null,"skill_md_sha":"ef94a4388cf1d6d1bda8716c144a214c4b55e1e6","skill_md_path":"skills/functional-ts/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/iwasa-kosui/functional-ts-principles/tree/main/skills/functional-ts"},"layout":"multi","source":"github","category":"functional-ts-principles","frontmatter":{"name":"functional-ts","license":"MIT","description":"Use when writing server-side TypeScript code involving domain models, use cases, repositories, state transitions, or business logic. Guides functional domain modeling with discriminated unions, pure functions, and Result types."},"skills_sh_url":"https://skills.sh/iwasa-kosui/functional-ts-principles/functional-ts"},"updatedAt":"2026-05-10T07:03:40.131Z"}}