{"id":"b6523bea-36f2-4cbc-9507-20c2a96dd6dd","shortId":"PH297A","kind":"skill","title":"functional-ts-ja","tagline":"サーバーサイドTypeScriptでドメインモデル、ユースケース、リポジトリ、状態遷移、ビジネスロジックを書くときに使用する。Discriminated Union、純粋関数、Result型による関数型ドメインモデリングをガイドする。","description":"# Functional Domain Modeling in TypeScript\n\nサーバーサイドTypeScriptでドメインモデルを書くときの原則。classベースのOOPではなく、TypeScriptの型システムを最大限に活用した関数型アプローチを採る。\n\n## 1. 型によるドメインモデリング\n\nDiscriminated Unionで状態を表現し、`kind` をdiscriminantとして統一する。`type`（`interface` ではなく）、Companion Object、Branded Types、`Readonly<>`、関数プロパティ記法、1概念1ファイル構成を使う。\n\n**バリデーションライブラリの検出:** プロジェクトの `package.json` の `dependencies` / `devDependencies` を確認:\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\n詳細: [domain-modeling.md](./domain-modeling.md)\n\n## 2. 関数による状態遷移\n\n純粋関数で状態遷移を表現する。関数の引数型が有効な遷移元を制約し、戻り値型が遷移先を明示する。無効な遷移はコンパイルエラーになる。`assertNever` で網羅性をチェックする。\n\n詳細: [state-modeling.md](./state-modeling.md)\n\n## 3. エラーハンドリング — Railway Oriented Programming\n\n例外をスローせず、Result型でエラーを値として扱う。エラー型はDiscriminated Unionで定義し、呼び出し元が網羅的にハンドルできるようにする。\n\n**ライブラリの検出:** プロジェクトの `package.json` の `dependencies` / `devDependencies` を確認:\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\n詳細: [error-handling.md](./error-handling.md)\n\n## 4. 境界の防御\n\n外部入力（APIリクエスト、DB結果、ファイル読み込み）はバリデーションライブラリのスキーマでランタイムバリデーションする。ドメイン層内部では型を信頼する。型アサーション（`as`）は使わない。PIIフィールドには `Sensitive<T>` ラッパーを適用する。\n\n詳細: [boundary-defense.md](./boundary-defense.md)\n\n## 5. 宣言的なスタイル\n\n配列の変換は `filter` / `map` / `reduce` でCompanion Objectの述語関数を使って宣言的に書く。ドメインイベントは不変レコードとしてモデリングする。\n\n詳細: [declarative-style.md](./declarative-style.md)\n\n## 6. テストデータ\n\nテストデータは `as const satisfies Type` で定義し、discriminantのリテラル型を保持しwideningを防ぐ。\n\n詳細: [test-data.md](./test-data.md)\n\n## 原則の適用について\n\nこれらは推奨であり厳格なルールではない。コンテキストに応じて判断してよいが、原則から逸脱する場合はその理由をコメントで明示すること。\n\n典型的な逸脱の正当理由:\n- 外部ライブラリがclass継承を要求する場合\n- パフォーマンス要件により不変データの生成コストが問題になる場合\n- チームの合意により異なるパターンが採用されている場合","tags":["functional","principles","iwasa-kosui","agent-skills"],"capabilities":["skill","source-iwasa-kosui","skill-functional-ts-ja","topic-agent-skills"],"categories":["functional-ts-principles"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/iwasa-kosui/functional-ts-principles/functional-ts-ja","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 (2,069 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:39.469Z","embedding":null,"createdAt":"2026-05-10T07:03:39.469Z","updatedAt":"2026-05-10T07:03:39.469Z","lastSeenAt":"2026-05-10T07:03:39.469Z","tsv":"'/arktype.md':61 '/boundary-defense.md':141 '/byethrow.md':104 '/declarative-style.md':153 '/domain-modeling.md':65 '/error-handling.md':124 '/fp-ts.md':112 '/neverthrow.md':98 '/option-t.md':120 '/result-libraries/byethrow.md':105 '/result-libraries/fp-ts.md':113 '/result-libraries/neverthrow.md':99 '/result-libraries/option-t.md':121 '/state-modeling.md':76 '/test-data.md':165 '/valibot.md':55 '/validation-libraries/arktype.md':62 '/validation-libraries/valibot.md':56 '/validation-libraries/zod.md':50 '/zod.md':49 '1':22 '1概念1ファイル構成を使う':37 '2':66 '3':77 '4':125 '5':142 '6':154 'apiリクエスト':128 'arktyp':57 'assertnev':72 'boundary-defense.md':140 'brand':33 'byethrow':100 'classベースのoopではなく':20 'companion':31 'const':158 'db結果':129 'declarative-style.md':152 'depend':42,91 'devdepend':43,92 'discrimin':10,24 'discriminantのリテラル型を保持しwideningを防ぐ':162 'domain':15 'domain-modeling.md':64 'error-handling.md':123 'filter':145 'fp':107 'fp-ts':106 'function':2,14 'functional-ts-ja':1 'interfac':29 'ja':4 'kind':26 'librari':48,54,60,97,103,111,119 'map':146 'model':16 'neverthrow':94 'object':32 'objectの述語関数を使って宣言的に書く':149 'option':115 'option-t':114 'orient':80 'package.json':40,89 'piiフィールドには':136 'program':81 'railway':79 'readon':35 'reduc':147 'result':96,102,110,118 'result-librari':95,101,109,117 'result型でエラーを値として扱う':83 'result型による関数型ドメインモデリングをガイドする':13 'satisfi':159 'sensit':137 'skill' 'skill-functional-ts-ja' 'source-iwasa-kosui' 'state-modeling.md':75 'test-data.md':164 'topic-agent-skills' 'ts':3,108 'type':28,34,160 'typescript':18 'typescriptの型システムを最大限に活用した関数型アプローチを採る':21 'union':11 'unionで定義し':85 'unionで状態を表現し':25 'valibot':51 'valid':47,53,59 'validation-librari':46,52,58 'zod':45 'これらは推奨であり厳格なルールではない':167 'でcompanion':148 'ではなく':30 'で定義し':161 'で網羅性をチェックする':73 'の':41,90 'はバリデーションライブラリのスキーマでランタイムバリデーションする':131 'は使わない':135 'をdiscriminantとして統一する':27 'を確認':44,93 'エラーハンドリング':78 'エラー型はdiscrimin':84 'コンテキストに応じて判断してよいが':168 'サーバーサイドtypescriptでドメインモデル':5 'サーバーサイドtypescriptでドメインモデルを書くときの原則':19 'チームの合意により異なるパターンが採用されている場合':173 'テストデータ':155 'テストデータは':156 'ドメインイベントは不変レコードとしてモデリングする':150 'ドメイン層内部では型を信頼する':132 'バリデーションライブラリの検出':38 'パフォーマンス要件により不変データの生成コストが問題になる場合':172 'ビジネスロジックを書くときに使用する':9 'ファイル読み込み':130 'プロジェクトの':39,88 'ユースケース':6 'ライブラリの検出':87 'ラッパーを適用する':138 'リポジトリ':7 '例外をスローせず':82 '典型的な逸脱の正当理由':170 '原則から逸脱する場合はその理由をコメントで明示すること':169 '原則の適用について':166 '呼び出し元が網羅的にハンドルできるようにする':86 '型によるドメインモデリング':23 '型アサーション':133 '境界の防御':126 '外部ライブラリがclass継承を要求する場合':171 '外部入力':127 '宣言的なスタイル':143 '戻り値型が遷移先を明示する':70 '無効な遷移はコンパイルエラーになる':71 '状態遷移':8 '純粋関数':12 '純粋関数で状態遷移を表現する':68 '詳細':63,74,122,139,151,163 '配列の変換は':144 '関数による状態遷移':67 '関数の引数型が有効な遷移元を制約し':69 '関数プロパティ記法':36","prices":[{"id":"df8ac766-c1cc-45ce-87df-00c48c22e9c4","listingId":"b6523bea-36f2-4cbc-9507-20c2a96dd6dd","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:39.469Z"}],"sources":[{"listingId":"b6523bea-36f2-4cbc-9507-20c2a96dd6dd","source":"github","sourceId":"iwasa-kosui/functional-ts-principles/functional-ts-ja","sourceUrl":"https://github.com/iwasa-kosui/functional-ts-principles/tree/main/skills/functional-ts-ja","isPrimary":false,"firstSeenAt":"2026-05-10T07:03:39.469Z","lastSeenAt":"2026-05-10T07:03:39.469Z"}],"details":{"listingId":"b6523bea-36f2-4cbc-9507-20c2a96dd6dd","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"iwasa-kosui","slug":"functional-ts-ja","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":"e09b3f7b8850406436247a04b3aecdc64621f14c","skill_md_path":"skills/functional-ts-ja/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/iwasa-kosui/functional-ts-principles/tree/main/skills/functional-ts-ja"},"layout":"multi","source":"github","category":"functional-ts-principles","frontmatter":{"name":"functional-ts-ja","license":"MIT","description":"サーバーサイドTypeScriptでドメインモデル、ユースケース、リポジトリ、状態遷移、ビジネスロジックを書くときに使用する。Discriminated Union、純粋関数、Result型による関数型ドメインモデリングをガイドする。"},"skills_sh_url":"https://skills.sh/iwasa-kosui/functional-ts-principles/functional-ts-ja"},"updatedAt":"2026-05-10T07:03:39.469Z"}}