{"id":18552459,"url":"https://github.com/andrejewski/tagmeme","last_synced_at":"2025-04-09T22:31:56.186Z","repository":{"id":68511816,"uuid":"99430202","full_name":"andrejewski/tagmeme","owner":"andrejewski","description":"Simple tagged unions","archived":false,"fork":false,"pushed_at":"2020-05-11T17:29:10.000Z","size":99,"stargazers_count":20,"open_issues_count":3,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-05T00:02:40.486Z","etag":null,"topics":["javascript","tagged-unions","variants"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andrejewski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-08-05T15:11:00.000Z","updated_at":"2024-02-25T15:32:07.000Z","dependencies_parsed_at":"2023-03-11T03:49:01.464Z","dependency_job_id":null,"html_url":"https://github.com/andrejewski/tagmeme","commit_stats":{"total_commits":36,"total_committers":2,"mean_commits":18.0,"dds":"0.16666666666666663","last_synced_commit":"f1bac6854be80fa9c585cd578e51e2b1afc181b3"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrejewski%2Ftagmeme","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrejewski%2Ftagmeme/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrejewski%2Ftagmeme/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrejewski%2Ftagmeme/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andrejewski","download_url":"https://codeload.github.com/andrejewski/tagmeme/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247563910,"owners_count":20958971,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","tagged-unions","variants"],"created_at":"2024-11-06T21:14:17.572Z","updated_at":"2025-04-09T22:31:55.849Z","avatar_url":"https://github.com/andrejewski.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tagmeme\n\u003e Tagged unions\n\n```sh\nnpm install tagmeme\n```\n\n[![npm](https://img.shields.io/npm/v/tagmeme.svg)](https://www.npmjs.com/package/tagmeme)\n[![Build Status](https://travis-ci.org/andrejewski/tagmeme.svg?branch=master)](https://travis-ci.org/andrejewski/tagmeme)\n[![Greenkeeper badge](https://badges.greenkeeper.io/andrejewski/tagmeme.svg)](https://greenkeeper.io/)\n\nTagmeme is a library for building tagged unions.\nThis project offers:\n\n- A concise API for pattern matching and variant constructors\n- Data-oriented tags that can be serialized and namespaced\n- Errors in development to ensure exhaustive pattern matching\n- Small size and zero-dependencies in production using dead code elimination\n\nLet's check it out.\n\n## Examples\n\n```js\nimport assert from 'assert'\nimport { union } from 'tagmeme'\n\nconst Result = union(['Ok', 'Err'])\n\nconst err = Result.Err(new Error('My error'))\n\nconst message = Result.match(err, {\n  Ok: () =\u003e 'No error',\n  Err: error =\u003e error.message\n})\n\nassert(message === 'My error')\n\nconst handle = Result.matcher({\n  Ok: () =\u003e 'No error',\n  Err: error =\u003e error.message\n})\n\nassert(handle(err) === 'My error')\n\nconst isError = Result.matches(err, Result.Err)\n\nassert(isError)\n```\n\n## Documentation\n\nThis package includes:\n\n- [`union(types, options)`](#union)\n- [`Union[type](data)`](#uniontype)\n- [`Union.match(tag, handlers, catchAll)`](#unionmatch)\n- [`Union.matcher(handlers, catchAll)`](#unionmatcher)\n- [`Union.matches(tag, variant)`](#unionmatches)\n- [`safeUnion(types, options)`](#safeunion)\n\n#### `union`\n\u003e `union(types: Array\u003cString\u003e[, options: { prefix: String }]): Union`\n\nCreate a tagged union. Throws if:\n  - `types` is not an array of unique strings\n  - any `types` are named \"match\", \"matcher\", or \"matches\"\n\nSee [`safeUnion`](#safeunion) if using arbitrary strings.\n\n#### `Union[type]`\n\u003e `Union[type](data: any): ({ type, data })`\n\nCreate a tag of the union containing `data` which can be retrieved via `Union.match`.\n\n```js\nimport assert from 'assert'\nimport { union } from 'tagmeme'\n\nconst Result = union(['Ok', 'Err'])\nconst result = Result.Ok('good stuff')\n\nassert(result.type === 'Ok')\nassert(result.data === 'good stuff')\n```\n\n#### `Union.match`\n\u003e `Union.match(tag, handlers[, catchAll: function])`\n\nPattern match on `tag` with a hashmap of `handlers` where keys are kinds and values are functions, with an optional `catchAll` if no handler matches the value.\nThrows if:\n  - `tag` is not of any of the union types\n  - `tag` does not match any type and there is no `catchAll`\n  - any `handlers` key is not a kind in the union\n  - any `handlers` value is not a function\n  - it handles all cases and there is a useless `catchAll`\n  - it does not handle all cases and there is no `catchAll`\n\n```js\nimport assert from 'assert'\nimport { union } from 'tagmeme'\n\nconst Result = union(['Ok', 'Err'])\nconst result = Result.Err('Request failed')\nconst status = Result.match(\n  result,\n  { Err: () =\u003e 400 },\n  () =\u003e 200\n})\n\nassert(status === 400)\n```\n\n#### `Union.matcher`\n\u003e `Union.matcher(handlers[, catchAll: function])`\n\nCreate a matching function which will take `tag` and `context` arguments.\nThis reduces the boilerplate of a function that delegates to `Union.match` with static handlers.\nThis is also a bit faster than `match` because the handler functions only need to be created once.\n\nUnlike with `match`, the second argument to handlers will be `context` to avoid the need for a closure.\n\n```js\nimport assert from 'assert'\nimport { union } from 'tagmeme'\n\nconst Result = union(['Ok', 'Err'])\nconst collectErrors = Result.matcher({\n  Ok: (_, errors) =\u003e errors,\n  Err: (error, errors) =\u003e errors.concat(error)\n})\n\nconst errors = collectErrors(Result.Err('Bad'), [])\nassert.deepEqual(errors, ['Bad'])\n```\n\n#### `Union.matches`\n\u003e `Union.matches(tag, variant: Variant): Boolean`\n\nDetermine whether a given `tag` is of `variant`.\n\n```js\nimport assert from 'assert'\nimport { union } from 'tagmeme'\n\nconst Result = union(['Ok', 'Err'])\nconst okTag = Result.Ok(1)\n\nassert(Result.matches(okTag, Result.Ok))\n```\n\n#### `safeUnion`\n\u003e `safeUnion(types: Array\u003cString\u003e[, options: { prefix: String }]): { methods, variants }`\n\nFor library authors accepting arbitrary strings for type names, `safeUnion` is `union` but returns distinct collections of methods and type variants.\nThis will not throw if a type is \"match\", \"matcher\", or \"matches\".\n\n## Name\n\n\u003e tagmeme |ˈtaɡmiːm|: a slot in a syntactic frame which may be filled by any member of a set of appropriate linguistic items.\n\nThis name is kind of fitting for a tagged union library.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrejewski%2Ftagmeme","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandrejewski%2Ftagmeme","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrejewski%2Ftagmeme/lists"}