{"id":"cac9a33a-3c4d-4518-b0b4-a52a8e677b29","shortId":"R8e6Vc","kind":"skill","title":"functional-ts-review","tagline":"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, ","description":"# Functional TypeScript Code Review\n\nReview server-side TypeScript code against the functional domain modeling principles defined in the `functional-ts` skill. This review uses the **same knowledge base** as `functional-ts` — every checklist item below corresponds to a section of that skill, and links to the authoritative description there.\n\n## Review Procedure\n\n1. **Load the principle knowledge first.** Before reading any code under review, read the following so that findings cite the canonical principle:\n   - [`../functional-ts/SKILL.md`](../functional-ts/SKILL.md) — the principle index\n   - [`../functional-ts/error-handling.md`](../functional-ts/error-handling.md)\n   - [`../functional-ts/boundary-defense.md`](../functional-ts/boundary-defense.md)\n   - [`../functional-ts/state-modeling.md`](../functional-ts/state-modeling.md)\n   - The validation library guide matching the project's `package.json` under [`../functional-ts/validation-libraries/`](../functional-ts/validation-libraries/) (`zod.md` / `valibot.md` / `arktype.md`)\n   - The Result library guide matching the project's `package.json` under [`../functional-ts/result-libraries/`](../functional-ts/result-libraries/) (`neverthrow.md` / `byethrow.md` / `fp-ts.md` / `option-t.md`)\n2. Read the files under review.\n3. Walk through the checklist below in the order of the principles. The numbering mirrors `functional-ts/SKILL.md`.\n4. When a violation is found, report it with the relevant principle, the reason it matters, and a fix.\n5. When something is not a violation but has room for improvement, communicate it as a suggestion.\n\n## Checklist\n\nThe checklist mirrors the structure of [`../functional-ts/SKILL.md`](../functional-ts/SKILL.md). Each item links back to the authoritative description.\n\n### 1. Type-Driven Domain Modeling\n\n#### 1.1 Are domain states modeled as Discriminated Unions?\n\nReference: [`../functional-ts/SKILL.md` §1 \"Represent State with Discriminated Unions\"](../functional-ts/SKILL.md)\n\nFlag: a single type with many `optional` properties and a `string` state field (e.g. `{ state: string; driverId?: string; startTime?: Date }`). Suggest splitting into per-state types unioned together so state-specific properties become required.\n\n#### 1.2 Is `kind` used as the unified discriminant?\n\nReference: [`../functional-ts/SKILL.md` §1 \"Use `kind` as the unified discriminant\"](../functional-ts/SKILL.md)\n\nFlag: discriminant property names other than `kind` (`type`, `status`, `state`, `_tag`, …). Suggest renaming to `kind` for codebase consistency.\n\n#### 1.3 Are classes used for domain models?\n\nReference: [`../functional-ts/SKILL.md` §1 \"Represent State with Discriminated Unions\"](../functional-ts/SKILL.md), and the Companion Object pattern.\n\nIf `class` defines domain entities or value objects, suggest migrating to Discriminated Union + Companion Object. Class inheritance required by an external library is a legitimate exception.\n\n#### 1.4 Is the Companion Object pattern followed?\n\nReference: [`../functional-ts/SKILL.md` §1 \"Companion Object Pattern\"](../functional-ts/SKILL.md)\n\nCheck that:\n- A type's related operations live on a `const` of the same name as the type.\n- Branded Type validation schemas are exposed as `.schema` on the companion object, not as standalone `XxxSchema` exports.\n- Domain logic is not scattered as free-standing `xxxAssignDriver` helpers when a companion object would naturally own them.\n\n#### 1.5 Is `interface` used for domain types?\n\nReference: [`../functional-ts/SKILL.md` §1 \"Use `type` (not `interface`)\"](../functional-ts/SKILL.md)\n\nDeclaration merging silently changes a type's shape. Domain types must be `type`. `interface` is acceptable only for library type augmentation.\n\n#### 1.6 Is method notation used inside type definitions?\n\nReference: [`../functional-ts/SKILL.md` §1 \"Use function property notation (not method notation)\"](../functional-ts/SKILL.md)\n\nMethod notation (`save(task: Task): Promise<void>`) makes parameters bivariant, allowing a narrower implementation (`save(task: DoingTask): …`) to type-check at injection sites. Suggest function property notation (`save: (task: Task) => Promise<void>`).\n\n#### 1.7 Are Branded Types applied to semantically distinct primitives?\n\nReference: [`../functional-ts/SKILL.md` §1 \"Distinguish meaning with Branded Types\"](../functional-ts/SKILL.md), plus the project's validation library guide under [`../functional-ts/validation-libraries/`](../functional-ts/validation-libraries/).\n\nFlag: `string` / `number` used directly for IDs and semantically distinct values (`UserId`, `OrderId`, `Email`, money amounts, …). Verify that brands use the validation library's brand feature when one is present (so `as` casts are unnecessary), or the `unique symbol` pattern when no library is used.\n\n#### 1.8 Are domain objects `Readonly<>`?\n\nReference: [`../functional-ts/SKILL.md` §1 \"Ensure immutability with `Readonly<>`\"](../functional-ts/SKILL.md)\n\nFlag: domain object types defined without `Readonly<…>` (or `readonly` per-property). State changes should produce new objects, not mutate properties.\n\n#### 1.9 Is the \"one concept per file\" rule followed?\n\nReference: [`../functional-ts/SKILL.md` §1 \"File structure: one concept per file\"](../functional-ts/SKILL.md)\n\nFlag: catch-all files (`types.ts`, `models.ts`, `domain.ts`) aggregating many domain types, especially when companion objects live elsewhere. Barrel files (`index.ts`) must only re-export.\n\n### 2. State Transitions via Functions\n\nReference: [`../functional-ts/SKILL.md` §2](../functional-ts/SKILL.md) and [`../functional-ts/state-modeling.md`](../functional-ts/state-modeling.md)\n\n#### 2.1 Do state transitions constrain source states by argument type?\n\nFlag: a transition function whose argument type is the union (`TaxiRequest`) instead of the specific source state (`Waiting`). The wider type allows callers to apply the transition to invalid source states.\n\n#### 2.2 Do `switch` statements over Discriminated Unions have `assertNever`?\n\nReference: [`../functional-ts/SKILL.md` §2 \"Exhaustiveness Checking\"](../functional-ts/SKILL.md)\n\nFlag: `switch` on `kind` without `default: return assertNever(x)`. Without it, adding a new variant will not produce a compile error.\n\n### 3. Error Handling — Railway Oriented Programming\n\nReference: [`../functional-ts/SKILL.md` §3](../functional-ts/SKILL.md), [`../functional-ts/error-handling.md`](../functional-ts/error-handling.md), and the project's Result library guide under [`../functional-ts/result-libraries/`](../functional-ts/result-libraries/).\n\n#### 3.1 Are exceptions thrown in the domain layer?\n\nFlag: `throw` in entities, value objects, or use cases. Suggest migrating to `Result`. Acceptable: `throw` inside `assertNever` (unreachable) and unexpected failures in the infrastructure layer.\n\n#### 3.2 Are error types Discriminated Unions?\n\nFlag: `Error` subclasses, free-form `string` error codes, or `Result<T, string>`. Suggest a Discriminated Union (`{ kind: \"DriverNotAvailable\"; driverId } | { kind: \"RequestAlreadyAssigned\" }`) so callers can branch exhaustively.\n\n#### 3.3 Are Result chains used instead of nested if/else?\n\nVerify that the project uses the matching Result library API (`.map`, `.andThen`, `Result.do`, …) rather than unwrapping immediately into branching code. Cite the matching guide under `../functional-ts/result-libraries/` for the correct combinator.\n\n### 4. Boundary Defense\n\nReference: [`../functional-ts/SKILL.md` §4](../functional-ts/SKILL.md), [`../functional-ts/boundary-defense.md`](../functional-ts/boundary-defense.md), and the project's validation library guide under [`../functional-ts/validation-libraries/`](../functional-ts/validation-libraries/).\n\n#### 4.1 Is schema validation present at every external boundary?\n\nFlag: API handlers, DB-result mappers, queue/message handlers, file/config loaders, or env-var readers that treat raw data as domain types without parsing it through a validation library schema (Zod / Valibot / ArkType).\n\n#### 4.2 Are `as` type assertions used?\n\nReference: [`../functional-ts/SKILL.md` §4 \"Do not use type assertions (`as`)\"](../functional-ts/SKILL.md)\n\nFlag every `as` and verify it falls into one of these acceptable cases:\n- External data: must be replaced by a validation schema parse.\n- `as` inside a Branded Type factory: acceptable when no validation library is used (`unique symbol` pattern).\n- Internal data: type inference should resolve it; if not, the type design is likely wrong.\n\n#### 4.3 Do PII fields use `Sensitive<T>`?\n\nReference: [`../functional-ts/SKILL.md` §4 \"PII Protection\"](../functional-ts/SKILL.md), [`../functional-ts/boundary-defense.md`](../functional-ts/boundary-defense.md)\n\nFlag: fields plausibly carrying personal information (name, email, phone, address, government IDs, payment details, health/diagnostic information, IP addresses) that are bare `string`/`number` rather than `Sensitive<T>`. Pay special attention to objects that may appear in logs or error messages. Verify that the validation schema auto-wraps such fields with `Sensitive.of`.\n\n### 5. Declarative Style\n\nReference: [`../functional-ts/SKILL.md` §5](../functional-ts/SKILL.md), [`../functional-ts/state-modeling.md`](../functional-ts/state-modeling.md)\n\n#### 5.1 Are array operations declarative?\n\nFlag: `for` / `for…of` loops that build up arrays imperatively when `filter` / `map` / `reduce` would express the intent directly. Suggest defining predicates on the companion object (e.g., `tasks.filter(Task.isActive)`).\n\n#### 5.2 Are domain events emitted as immutable records?\n\nFlag: state-change code that mutates a shared event log, or that omits domain events entirely when the state-modeling guidance calls for them. Events should be `Readonly<{ eventId; eventAt; eventName; payload; aggregateId }>` and recorded separately from the repository.\n\n### 6. Test Data\n\nReference: [`../functional-ts/SKILL.md` §6](../functional-ts/SKILL.md)\n\n#### 6.1 Is `as const satisfies Type` used for fixtures?\n\nFlag: test fixtures typed with `: Type =` or with `as Type`, which widen discriminant literals to `string`. Suggest `as const satisfies Type` so `kind` keeps its literal type.\n\n## How to Write Findings\n\nEach finding should include:\n\n1. **What the problem is**: the specific location in the code (`path:line`).\n2. **Why it is a problem**: the principle (with a link back to `../functional-ts/...`) and the risk of violating it.\n3. **How to fix it**: a code example showing the corrected version.\n\n```\n### Use of method notation\n\n`src/repository/task-repository.ts:15`\n\n`save(task: Task): Promise<void>` uses method notation. Per\n[`../functional-ts/SKILL.md` §1 \"Use function property notation\"](../functional-ts/SKILL.md),\nparameters become bivariant under method notation, so a narrower implementation such as\n`save(task: DoingTask): Promise<void>` will pass type checking at the injection site.\n\nSuggested fix:\n\\`\\`\\`typescript\ntype TaskRepository = {\n  save: (task: Task) => Promise<void>;\n};\n\\`\\`\\`\n```\n\n## Severity\n\n| Severity | Item | Reason |\n|----------|------|--------|\n| High | `as` type assertions (4.2) | Direct cause of runtime errors |\n| High | Unprotected PII (4.3) | Risk of compliance violations |\n| High | Missing schema validation at external boundaries (4.1) | Direct cause of runtime errors |\n| High | Missing Branded Types on semantically distinct primitives (1.7) | Cross-domain ID confusion at runtime |\n| Medium | Class usage (1.3) | Reduced type safety when extended |\n| Medium | Optional-property state modeling instead of Discriminated Union (1.1) | Invalid states become representable |\n| Medium | Use of `throw` in domain layer (3.1) | Inconsistent error handling |\n| Medium | Non-Discriminated-Union error types (3.2) | Callers cannot branch exhaustively |\n| Medium | Missing `assertNever` (2.2) | New variants slip through unhandled |\n| Medium | State transitions accepting the union type (2.1) | Invalid transitions compile |\n| Medium | Catch-all type files (1.9) | Circular dependencies, separation of types from behavior |\n| Medium | Companion Object violations / standalone schema export (1.4) | Implementation detail leakage |\n| Low | Method notation (1.6) | Issue only manifests under specific conditions |\n| Low | `interface` usage for domain types (1.5) | Declaration merging accidents are rare |\n| Low | Non-`Readonly<>` domain types (1.8) | Mutation is usually caught in review even without the type |\n| Low | Discriminant other than `kind` (1.2) | Stylistic inconsistency rather than a defect |\n| Low | Imperative array loops (5.1) | Readability rather than correctness |\n| Low | Missing domain events (5.2) | Depends on whether event sourcing is in scope |\n| Low | Fixtures without `as const satisfies` (6.1) | Caught by tests in practice |","tags":["functional","review","principles","iwasa-kosui","agent-skills"],"capabilities":["skill","source-iwasa-kosui","skill-functional-ts-review","topic-agent-skills"],"categories":["functional-ts-principles"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/iwasa-kosui/functional-ts-principles/functional-ts-review","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 (12,774 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.937Z","embedding":null,"createdAt":"2026-05-10T07:03:39.937Z","updatedAt":"2026-05-10T07:03:39.937Z","lastSeenAt":"2026-05-10T07:03:39.937Z","tsv":"'/functional-ts':1269 '/functional-ts/boundary-defense.md':126,127,910,911,1047,1048 '/functional-ts/error-handling.md':124,125,786,787 '/functional-ts/result-libraries':155,156,796,797,898 '/functional-ts/skill.md':119,120,229,230,254,261,307,315,342,349,389,394,457,463,494,503,545,552,614,620,652,660,693,695,750,754,783,785,907,909,972,980,1042,1046,1104,1106,1196,1198,1302,1308 '/functional-ts/state-modeling.md':128,129,697,698,1107,1108 '/functional-ts/validation-libraries':140,141,561,562,920,921 '/skill.md':185 '1':97,239,255,308,343,390,458,495,546,615,653,1243,1303 '1.1':245,1412 '1.2':298,1528 '1.3':334,1396 '1.4':381,1481 '1.5':449,1501 '1.6':485,1488 '1.7':535,1385 '1.8':608,1512 '1.9':642,1466 '15':1293 '2':161,687,694,751,1256 '2.1':699,1456 '2.2':740,1443 '3':167,776,784,1276 '3.1':798,1424 '3.2':831,1435 '3.3':864 '4':186,903,908,973,1043 '4.1':922,1371 '4.2':965,1350 '4.3':1035,1359 '5':205,1100,1105 '5.1':1109,1539 '5.2':1143,1548 '6':1192,1197 '6.1':1199,1563 'accept':479,819,992,1010,1452 'accid':1504 'ad':766 'address':1058,1066 'adher':14 'aggreg':669 'aggregateid':1185 'allow':513,730 'amount':578 'andthen':884 'api':882,932 'appear':1082 'appli':539,733 'argument':707,714 'arktyp':964 'arktype.md':144 'array':1111,1122,1537 'assert':969,978,1349 'assertnev':748,762,822,1442 'attent':1077 'augment':484 'authorit':92,237 'auto':1094 'auto-wrap':1093 'back':234,1267 'bare':1069 'barrel':679 'base':72 'becom':296,1310,1415 'behavior':1473 'bivari':512,1311 'boundari':904,930,1370 'branch':862,891,1438 'brand':35,413,537,550,581,587,1007,1379 'build':1120 'byethrow.md':158 'call':1174 'caller':731,860,1436 'cannot':1437 'canon':117 'carri':1052 'case':814,993 'cast':595 'catch':663,1462 'catch-al':662,1461 'caught':1516,1564 'caus':1352,1373 'chain':867 'chang':467,634,1154 'check':20,395,523,753,1328 'checklist':78,171,222,224 'circular':1467 'cite':115,893 'class':336,356,370,1394 'code':12,45,52,106,845,892,1155,1253,1282 'codebas':332 'combin':902 'communic':217 'companion':33,352,368,384,391,423,443,675,1138,1475 'compil':774,1459 'complianc':1362 'concept':646,657 'condit':1494 'confus':1390 'consist':333 'const':405,1202,1226,1561 'constrain':703 'correct':901,1286,1543 'correspond':81 'cross':1387 'cross-domain':1386 'data':950,995,1021,1194 'date':281 'db':935 'db-result':934 'declar':464,1101,1113,1502 'default':760 'defect':1534 'defens':905 'defin':59,357,625,1134 'definit':492 'depend':1468,1549 'descript':93,238 'design':1031 'detail':1062,1483 'direct':567,1132,1351,1372 'discrimin':31,251,259,305,314,317,347,366,745,835,852,1220,1410,1431,1524 'distinct':542,572,1383 'distinguish':547 'doingtask':519,1323 'domain':17,56,243,247,339,358,430,454,472,610,622,671,804,952,1145,1165,1388,1422,1499,1510,1546 'domain.ts':668 'driven':242 'driverid':278,856 'drivernotavail':855 'e.g':275,1140 'elsewher':678 'email':576,1056 'emit':1147 'enforc':24 'ensur':616 'entir':1167 'entiti':359,809 'env':944 'env-var':943 'error':775,777,833,838,844,1086,1355,1376,1426,1433 'especi':673 'even':1519 'event':1146,1160,1166,1177,1547,1552 'eventat':1182 'eventid':1181 'eventnam':1183 'everi':77,928,982 'exampl':1283 'except':380,800 'exhaust':752,863,1439 'export':429,686,1480 'expos':418 'express':1129 'extend':1401 'extern':375,929,994,1369 'factori':1009 'failur':826 'fall':987 'featur':588 'field':274,1038,1050,1097 'file':38,164,648,654,659,665,680,1465 'file/config':940 'filter':1125 'find':114,1238,1240 'first':102 'fix':204,1279,1334 'fixtur':1207,1210,1558 'flag':262,316,563,621,661,709,755,806,837,931,981,1049,1114,1151,1208 'follow':111,387,650 'form':842 'found':191 'fp-ts.md':159 'free':437,841 'free-form':840 'free-stand':436 'function':2,16,28,43,55,63,75,183,497,528,691,712,1305 'functional-t':27,62,74,182 'functional-ts-review':1 'govern':1059 'guid':133,148,559,794,896,918 'guidanc':1173 'handl':778,1427 'handler':933,939 'health/diagnostic':1063 'helper':440 'high':1346,1356,1364,1377 'id':569,1060,1389 'if/else':872 'immedi':889 'immut':37,617,1149 'imper':1123,1536 'implement':516,1318,1482 'improv':216 'includ':1242 'inconsist':1425,1530 'index':123 'index.ts':681 'infer':1023 'inform':1054,1064 'infrastructur':829 'inherit':371 'inject':525,1331 'insid':490,821,1005 'instead':720,869,1408 'intent':1131 'interfac':451,462,477,1496 'intern':1020 'invalid':737,1413,1457 'ip':1065 'issu':1489 'item':79,232,1344 'keep':1231 'kind':300,310,322,330,758,854,857,1230,1527 'knowledg':71,101 'layer':805,830,1423 'leakag':1484 'legitim':379 'librari':132,147,376,482,558,585,605,793,881,917,960,1014 'like':1033 'line':1255 'link':89,233,1266 'liter':1221,1233 'live':402,677 'load':98 'loader':941 'locat':1250 'log':1084,1161 'logic':431 'loop':1118,1538 'low':1485,1495,1507,1523,1535,1544,1557 'make':510 'mani':267,670 'manifest':1491 'map':883,1126 'mapper':937 'match':134,149,879,895 'matter':201 'may':1081 'mean':548 'medium':1393,1402,1417,1428,1440,1449,1460,1474 'merg':465,1503 'messag':1087 'method':487,501,504,1290,1299,1313,1486 'migrat':364,816 'mirror':181,225 'miss':1365,1378,1441,1545 'model':18,57,244,249,340,1172,1407 'models.ts':667 'money':577 'must':474,682,996 'mutat':640,1157,1513 'name':319,409,1055 'narrow':515,1317 'natur':446 'nest':871 'neverthrow.md':157 'new':637,768,1444 'non':1430,1508 'non-discriminated-union':1429 'notat':488,499,502,505,530,1291,1300,1307,1314,1487 'number':180,565,1071 'object':34,353,362,369,385,392,424,444,611,623,638,676,811,1079,1139,1476 'omit':1164 'one':590,645,656,989 'oper':401,1112 'option':268,1404 'option-t.md':160 'optional-properti':1403 'order':175 'orderid':575 'orient':780 'package.json':138,153 'paramet':511,1309 'pars':955,1003 'pass':1326 'path':1254 'pattern':354,386,393,602,1019 'pay':1075 'payload':1184 'payment':1061 'per':286,631,647,658,1301 'per-properti':630 'per-stat':285 'person':1053 'phone':1057 'pii':1037,1044,1358 'plausibl':1051 'plus':553 'practic':1568 'predic':1135 'present':592,926 'primit':543,1384 'principl':19,23,58,100,118,122,178,197,1263 'problem':1246,1261 'procedur':96 'produc':636,772 'program':781 'project':136,151,555,790,876,914 'promis':509,534,1297,1324,1341 'properti':269,295,318,498,529,632,641,1306,1405 'protect':1045 'pure':40 'queue/message':938 'railway':779 'rare':1506 'rather':886,1072,1531,1541 'raw':949 're':685 're-export':684 'read':104,109,162 'readabl':1540 'reader':946 'readon':612,619,627,629,1180,1509 'reason':199,1345 'record':1150,1187 'reduc':1127,1397 'refer':253,306,341,388,456,493,544,613,651,692,749,782,906,971,1041,1103,1195 'relat':400 'relev':196 'renam':328 'replac':998 'report':192 'repositori':1191 'repres':256,344 'represent':1416 'requestalreadyassign':858 'requir':297,372 'resolv':1025 'result':146,792,818,847,866,880,936 'result.do':885 'return':761 'review':4,7,46,47,67,95,108,166,1518 'risk':1272,1360 'room':214 'rule':649 'runtim':1354,1375,1392 'safeti':1399 'satisfi':1203,1227,1562 'save':506,517,531,1294,1321,1338 'scatter':434 'schema':416,420,924,961,1002,1092,1366,1479 'scope':1556 'section':84 'semant':541,571,1382 'sensit':1040,1074 'sensitive.of':1099 'separ':1188,1469 'server':10,49 'server-sid':9,48 'sever':1342,1343 'shape':471 'share':1159 'show':1284 'side':11,50 'silent':466 'singl':264 'site':526,1332 'skill':30,65,87 'skill-functional-ts-review' 'slip':1446 'someth':207 'sourc':704,724,738,1553 'source-iwasa-kosui' 'special':1076 'specif':294,723,1249,1493 'split':283 'src/repository/task-repository.ts':1292 'stand':438 'standalon':427,1478 'starttim':280 'state':41,248,257,273,276,287,293,325,345,633,688,701,705,725,739,1153,1171,1406,1414,1450 'state-chang':1152 'state-model':1170 'state-specif':292 'statement':743 'status':324 'string':272,277,279,564,843,849,1070,1223 'structur':39,227,655 'style':1102 'stylist':1529 'subclass':839 'suggest':221,282,327,363,527,815,850,1133,1224,1333 'switch':742,756 'symbol':601,1018 'tag':326 'task':507,508,518,532,533,1295,1296,1322,1339,1340 'task.isactive':1142 'taskrepositori':1337 'tasks.filter':1141 'taxirequest':719 'test':1193,1209,1566 'throw':807,820,1420 'thrown':801 'togeth':290 'topic-agent-skills' 'transit':42,689,702,711,735,1451,1458 'treat':948 'ts':3,29,64,76,184 'type':36,241,265,288,323,398,412,414,455,460,469,473,476,483,491,522,538,551,624,672,708,715,729,834,953,968,977,1008,1022,1030,1204,1211,1213,1217,1228,1234,1327,1336,1348,1380,1398,1434,1455,1464,1471,1500,1511,1522 'type-check':521 'type-driven':240 'types.ts':666 'typescript':8,44,51,1335 'unexpect':825 'unhandl':1448 'unifi':304,313 'union':32,252,260,289,348,367,718,746,836,853,1411,1432,1454 'uniqu':600,1017 'unnecessari':597 'unprotect':1357 'unreach':823 'unwrap':888 'usag':1395,1497 'use':5,68,301,309,337,452,459,489,496,566,582,607,813,868,877,970,976,1016,1039,1205,1288,1298,1304,1418 'userid':574 'usual':1515 'valibot':963 'valibot.md':143 'valid':131,415,557,584,916,925,959,1001,1013,1091,1367 'valu':361,573,810 'var':945 'variant':769,1445 'verifi':579,873,985,1088 'version':1287 'via':690 'violat':189,211,1274,1363,1477 'wait':726 'walk':168 'whether':1551 'whose':713 'widen':1219 'wider':728 'without':626,759,764,954,1520,1559 'would':445,1128 'wrap':1095 'write':1237 'wrong':1034 'x':763 'xxxassigndriv':439 'xxxschema':428 'zod':962 'zod.md':142","prices":[{"id":"95280e68-54a2-4705-a476-587ffc0bb05c","listingId":"cac9a33a-3c4d-4518-b0b4-a52a8e677b29","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.937Z"}],"sources":[{"listingId":"cac9a33a-3c4d-4518-b0b4-a52a8e677b29","source":"github","sourceId":"iwasa-kosui/functional-ts-principles/functional-ts-review","sourceUrl":"https://github.com/iwasa-kosui/functional-ts-principles/tree/main/skills/functional-ts-review","isPrimary":false,"firstSeenAt":"2026-05-10T07:03:39.937Z","lastSeenAt":"2026-05-10T07:03:39.937Z"}],"details":{"listingId":"cac9a33a-3c4d-4518-b0b4-a52a8e677b29","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"iwasa-kosui","slug":"functional-ts-review","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":"fccbb77079bad88d1759caada0c8995fb346ebaa","skill_md_path":"skills/functional-ts-review/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/iwasa-kosui/functional-ts-principles/tree/main/skills/functional-ts-review"},"layout":"multi","source":"github","category":"functional-ts-principles","frontmatter":{"name":"functional-ts-review","license":"MIT","description":"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."},"skills_sh_url":"https://skills.sh/iwasa-kosui/functional-ts-principles/functional-ts-review"},"updatedAt":"2026-05-10T07:03:39.937Z"}}