{"_id":"@detaditya/yamin","name":"@detaditya/yamin","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@detaditya/yamin","version":"0.1.0","description":"Easy yet powerful functional data type utilities","type":"module","license":"MIT","repository":{"type":"git","url":"git+https://github.com/deta-aditya/yamin.git"},"keywords":["functional","option","result","maybe","either","monad","typescript"],"main":"dist/index.cjs","module":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"import":"./dist/index.js","require":"./dist/index.cjs","types":"./dist/index.d.ts"}},"scripts":{"build":"bunup","test":"vitest run","test:watch":"vitest","typecheck":"tsc --noEmit"},"devDependencies":{"@types/bun":"latest","@vitest/coverage-v8":"^4.1.4","bunup":"^0.16.31","vitest":"^4.1.2"},"peerDependencies":{"typescript":"^5"},"_id":"@detaditya/yamin@0.1.0","gitHead":"ea6434388e8cad49cab2b9a9c257e5bbe31bd628","bugs":{"url":"https://github.com/deta-aditya/yamin/issues"},"homepage":"https://github.com/deta-aditya/yamin#readme","_nodeVersion":"22.17.1","_npmVersion":"10.9.2","dist":{"integrity":"sha512-KGk6wCXrdI7NO08Fc/1f+3Gc81TL9lG72NiRDV4Df1mCQPPFaacgc8FPNDgCQRwI4D3X0zzEv5qQals1sEAvkg==","shasum":"3f939cae08689626597bed29f736d541579c2e5f","tarball":"https://registry.npmjs.org/@detaditya/yamin/-/yamin-0.1.0.tgz","fileCount":6,"unpackedSize":17630,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDKEVHuKX9tWlDDfMSR6kMkI0VvCLqUz7YfDCCCe67+BAIgIdjYKWKidLsH9NnyO7QTl9m/cRsdWJqejMRytBQaPD4="}]},"_npmUser":{"name":"deta","email":"muhammaddetaaditya@gmail.com"},"directories":{},"maintainers":[{"name":"deta","email":"muhammaddetaaditya@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/yamin_0.1.0_1780814731201_0.5106464580675822"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-07T06:45:31.019Z","0.1.0":"2026-06-07T06:45:31.336Z","modified":"2026-06-07T06:45:31.591Z"},"maintainers":[{"name":"deta","email":"muhammaddetaaditya@gmail.com"}],"description":"Easy yet powerful functional data type utilities","homepage":"https://github.com/deta-aditya/yamin#readme","keywords":["functional","option","result","maybe","either","monad","typescript"],"repository":{"type":"git","url":"git+https://github.com/deta-aditya/yamin.git"},"bugs":{"url":"https://github.com/deta-aditya/yamin/issues"},"license":"MIT","readme":"# yamin\n\n[![CI](https://github.com/deta-aditya/yamin/actions/workflows/ci.yml/badge.svg)](https://github.com/deta-aditya/yamin/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/deta-aditya/yamin/graph/badge.svg)](https://codecov.io/gh/deta-aditya/yamin)\n[![npm](https://img.shields.io/npm/v/@detaditya/yamin)](https://www.npmjs.com/package/@detaditya/yamin)\n\nEasy yet powerful functional data type utilities.\n\n## Motivation\n\nTypeScript has discriminated unions built into its type system, but building them by hand is tedious — you write the type, then the constructors, then the type guards, then the matcher, all separately and all by hand. One renamed variant and you're fixing four different spots.\n\n**yamin** collapses that boilerplate into a single `Union` call:\n\n- **Constructors** — one per variant, derived automatically from the definition.\n- **Type guards** — `isVariantName(value)` predicates generated for every variant.\n- **`match`** — exhaustive pattern matching with an optional `_` catch-all, enforced at the type level.\n\n## Installation\n\n```bash\nnpm install @detaditya/yamin\n# or\nbun add @detaditya/yamin\n```\n\n## Union\n\n`Union` creates a discriminated union from a variant definition. Each variant is either a plain `null` (no payload) or `data<T>()` (carries a typed payload).\n\n### Creating a Union\n\n```ts\nimport { Union, type InferUnion } from \"@detaditya/yamin\";\n\nconst DataStatuses = Union(data => ({\n  idle: null,\n  loading: data<{ progress: number }>(),\n  done: data<{ result: string }>(),\n  failed: data<{ code: number; message: string }>(),\n}))\n\ntype DataStatus = InferUnion<typeof DataStatuses>\n```\n\n### Constructors\n\nEach variant key becomes a constructor on the union object. Null variants take no arguments; data variants require an object payload.\n\n```ts\nconst idle    = DataStatuses.idle()\nconst loading = DataStatuses.loading({ progress: 50 })\nconst done    = DataStatuses.done({ result: \"all good\" })\nconst failed  = DataStatuses.failed({ code: 404, message: \"not found\" })\n```\n\n### Type Guards\n\nA `isVariantName` predicate is generated for every variant and narrows the type when used in a conditional.\n\n```ts\nconst status: DataStatus = DataStatuses.loading({ progress: 50 })\n\nif (DataStatuses.isLoading(status)) {\n  console.log(status.payload.progress) // TypeScript knows this is the loading variant\n}\n\nDataStatuses.isIdle(status)    // false\nDataStatuses.isDone(status)    // false\nDataStatuses.isFailed(status)  // false\n```\n\n### Pattern Matching\n\n`match` dispatches to the handler for the active variant. Either cover every variant (exhaustive) or cover a subset and supply a `_` catch-all.\n\n```ts\n// Exhaustive — all variants handled\nconst message = DataStatuses.match(status, {\n  idle:    ()                     => \"Waiting...\",\n  loading: ({ progress })         => `Loading ${progress}%`,\n  done:    ({ result })           => `Done: ${result}`,\n  failed:  ({ code, message })    => `Error ${code}: ${message}`,\n})\n\n// Partial with catch-all\nconst label = DataStatuses.match(status, {\n  loading: ({ progress }) => `${progress}%`,\n  _: () => \"Not loading\",\n})\n```\n\n### Inferring the Union Type\n\nUse `InferUnion` to derive the instance type from a union object so you only define the shape once.\n\n```ts\nconst Actions = Union(data => ({\n  changeName: data<{ name: string }>(),\n  increment:  null,\n  decrement:  null,\n}))\n\ntype Action = InferUnion<typeof Actions>\n// { kind: \"changeName\"; payload: { name: string } }\n// | { kind: \"increment\"; payload: null }\n// | { kind: \"decrement\"; payload: null }\n```\n\n### Real-world Example: Reducer\n\n```ts\ntype State = { name: string; count: number }\n\nconst Actions = Union(data => ({\n  changeName: data<{ name: string }>(),\n  increment:  null,\n  decrement:  null,\n}))\ntype Action = InferUnion<typeof Actions>\n\nconst reducer = (state: State, action: Action): State =>\n  Actions.match(action, {\n    changeName: ({ name }) => ({ ...state, name }),\n    increment:  ()         => ({ ...state, count: state.count + 1 }),\n    decrement:  ()         => ({ ...state, count: state.count - 1 }),\n  })\n```\n\n### Real-world Example: View Rendering\n\n```ts\nconst DataStatuses = Union(data => ({\n  loading: null,\n  success: data<{ message: string }>(),\n  error:   data<{ code: number; message: string }>(),\n}))\ntype DataStatus = InferUnion<typeof DataStatuses>\n\nconst render = (status: DataStatus): string =>\n  DataStatuses.match(status, {\n    loading: ()                  => \"<p>Loading...</p>\",\n    success: ({ message })       => `<p>Success: ${message}</p>`,\n    error:   ({ code, message }) => `<p>Error ${code}: ${message}</p>`,\n  })\n```\n\n---\n\n## Roadmap\n\n- [ ] Additional data type utilities\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-2ef492341c4a14e2d418fd1256d8a788"}