{"id":16349312,"url":"https://github.com/stevemao/fp-ts-extras","last_synced_at":"2025-10-07T01:52:48.016Z","repository":{"id":46639294,"uuid":"306872107","full_name":"stevemao/fp-ts-extras","owner":"stevemao","description":"fp-ts extra functions and utilities","archived":false,"fork":false,"pushed_at":"2021-10-02T10:08:06.000Z","size":1084,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-24T22:37:49.090Z","etag":null,"topics":["fp","fp-ts","functional-programming","hacktoberfest"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stevemao.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-10-24T11:49:19.000Z","updated_at":"2023-04-11T15:38:19.000Z","dependencies_parsed_at":"2022-09-07T23:13:11.138Z","dependency_job_id":null,"html_url":"https://github.com/stevemao/fp-ts-extras","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/stevemao/fp-ts-extras","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevemao%2Ffp-ts-extras","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevemao%2Ffp-ts-extras/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevemao%2Ffp-ts-extras/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevemao%2Ffp-ts-extras/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stevemao","download_url":"https://codeload.github.com/stevemao/fp-ts-extras/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevemao%2Ffp-ts-extras/sbom","scorecard":{"id":852332,"data":{"date":"2025-08-11","repo":{"name":"github.com/stevemao/fp-ts-extras","commit":"805c48431a80db7ef813a15159c6fca96b2207ff"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.3,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/29 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 2 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"22 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-6fc8-4gx4-v693","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T22:51:51.343Z","repository_id":46639294,"created_at":"2025-08-23T22:51:51.343Z","updated_at":"2025-08-23T22:51:51.343Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278708030,"owners_count":26031932,"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","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["fp","fp-ts","functional-programming","hacktoberfest"],"created_at":"2024-10-11T00:59:01.638Z","updated_at":"2025-10-07T01:52:48.001Z","avatar_url":"https://github.com/stevemao.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003e fp-ts extra functions and utilities\n\n## Array\n\n### groupBy\n\n```ts\nimport { groupBy } from \"fp-ts-extras/lib/Array\";\n\nassert.deepStrictEqual(groupBy(eqNumber)([1, 1, 2, 3, 3, 4]), [\n  [1, 1],\n  [2],\n  [3, 3],\n  [4],\n]);\n```\n\n## Option\n\n### partial\n\n\u003e Drop-in replacement of `t.partial`\n\nInstead of returning `A | undefined`, it returns `Option\u003cA\u003e`\n\n```ts\nimport { partial } from \"fp-ts-extras/lib/Option\";\n\nconst B = partial({\n  bar: t.number,\n});\n```\n\n```ts\nimport * as t from \"io-ts\";\n\nconst User = t.type({\n  userId: t.number,\n  name: t.string,\n});\n\nconst PartialUser = t.partial(User.props);\n\ntype PartialUser = t.TypeOf\u003ctypeof PartialUser\u003e;\n\n// same as\ntype PartialUser = {\n  name: Option\u003cstring\u003e;\n  age: Option\u003cnumber\u003e;\n};\n```\n\n## Function\n\n### memPipe\n\nProblem: I have a `task` and if I call\n\n```ts\ntask();\ntask();\n```\n\nit fires the internal promise twice. The expected behaviour is it should only fire once. The second call returns the same result as the first one.\n\nUse case: I have 3 tasks: `t1`, `t2`, `t3`. `tA` is called once `t1` and `t2` is done. `tB` is called once `t1` and `t3` is done. `tC` is called once `t2` and `t3` is done. With raw promise I could do\n\n```ts\nPromise.all([\n   Promise.all([t1, t2]).then(_ =\u003e tA)\n   Promise.all([t2, t3]).then(_ =\u003e tC)\n   Promise.all([t1, t3]).then(_ =\u003e tB)\n]).then(...)\n```\n\nBut with Task\n\n```ts\nsequence([\n   pipe(sequence([t1, t2])), chain(_ =\u003e tA)),\n   pipe(sequence([t2, t3]), chain(_ =\u003e tC)),\n   pipe(sequence([t1, t3]), chain(_ =\u003e tB)),\n])\n...\n```\n\nside effects of `t1`, `t2`, `t3` will be fired twice each. `memPipe` will come in handy\n\n```ts\nimport { memPipe } from \"fp-ts-extras/lib/Function\";\n\nconst t1 = memPipe(...)\nconst t2 = memPipe(...)\nconst t3 = memPipe(...)\n\nsequence([\n   pipe(sequence([t1, t2])), chain(_ =\u003e tA)),\n   pipe(sequence([t2, t3]), chain(_ =\u003e tC)),\n   pipe(sequence([t1, t3]), chain(_ =\u003e tB)),\n])\n```\n\nEach task only performs side effect once.\n\n## JSON\n\n\u003e encode/decode automatically when you stringify/parse\n\nWhy? You can use your preferred algebraic data types in your business logic, and can be converted to traditional json automatically when you do http request or save stuff to db, and vice versa.\n\n```ts\nconst T = t.type({\n  foo: optionFromNullable(t.string),\n});\n\nconst result = stringify(T, {\n  foo: O.of(\"abc\"),\n});\n// right '{\"foo\":\"abc\"}'\n\nconst result = parse(T, '{\"foo\":\"abc\"}');\n/*\nright {\n  foo: O.of(\"abc\"),\n}\n*/\n```\n\n## Record\n\n### union\n\n```ts\nimport { union } from \"fp-ts-extras/lib/Record\";\n\nassert.deepStrictEqual(\n  union([\n    {\n      foo: \"foo\",\n    },\n    {\n      bar: \"bar\",\n    },\n  ]),\n  {\n    foo: \"foo\",\n    bar: \"bar\",\n  }\n);\n```\n\n## String\n\n```ts\nimport { split, join } from \"fp-ts-extras/lib/String\";\nimport { pipe } from \"fp-ts/lib/Function\";\nimport * as assert from \"assert\";\n\nconst result = pipe(\"a,b,c\", split(\",\"), join(\":\"));\n\nassert.deepStrictEqual(result, \"a:b:c\");\n```\n\n## TaskEither\n\n### decode\n\n\u003e Decode with error to reduce boilerplate\n\n```ts\nimport { decode } from \"fp-ts-extras/lib/TaskEither\";\nimport * as t from \"io-ts\";\nimport { pipe } from \"fp-ts/lib/Function\";\n\npipe(\n  decode(t.string, null)\n  // compose with other `TaskEither`s\n);\n```\n\n## Tuple\n\n\u003e Various useful functions on tuples, overloaded on tuple size.\n\n## UUID\n\n\u003e UUID generator that returns type `UUID`\n\n# Related projects\n\n- https://github.com/gcanti/fp-ts-contrib\n- https://github.com/samhh/fp-ts-std\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstevemao%2Ffp-ts-extras","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstevemao%2Ffp-ts-extras","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstevemao%2Ffp-ts-extras/lists"}