{"id":26221850,"url":"https://github.com/b00gizm/typed-chain","last_synced_at":"2026-05-17T23:34:33.911Z","repository":{"id":181179869,"uuid":"666074884","full_name":"b00gizm/typed-chain","owner":"b00gizm","description":"A type-safe way to combine interdependent functions into a callable chain","archived":false,"fork":false,"pushed_at":"2023-07-14T11:28:28.000Z","size":87,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-30T05:24:32.333Z","etag":null,"topics":["functional-programming","generic-programming","type-safe","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/b00gizm.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null}},"created_at":"2023-07-13T16:45:22.000Z","updated_at":"2023-07-14T11:21:56.000Z","dependencies_parsed_at":"2023-07-14T11:44:53.369Z","dependency_job_id":null,"html_url":"https://github.com/b00gizm/typed-chain","commit_stats":null,"previous_names":["b00gizm/typed-chain"],"tags_count":1,"template":false,"template_full_name":"b00gizm/nodejs-typescript-template","purl":"pkg:github/b00gizm/typed-chain","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/b00gizm%2Ftyped-chain","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/b00gizm%2Ftyped-chain/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/b00gizm%2Ftyped-chain/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/b00gizm%2Ftyped-chain/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/b00gizm","download_url":"https://codeload.github.com/b00gizm/typed-chain/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/b00gizm%2Ftyped-chain/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33159104,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-17T22:39:12.733Z","status":"ssl_error","status_checked_at":"2026-05-17T22:39:10.741Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["functional-programming","generic-programming","type-safe","typescript"],"created_at":"2025-03-12T16:32:20.793Z","updated_at":"2026-05-17T23:34:33.893Z","avatar_url":"https://github.com/b00gizm.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# typed-chain\n\n[![npm version](https://badge.fury.io/js/@b00gizm%2Ftyped-chain.svg)](https://badge.fury.io/js/@b00gizm%2Ftyped-chain)\n\nA type-safe way to combine interdependent functions into a callable chain.\n\n```typescript\nimport { chain } from '@b00gizm/typed-chain'\n\nconst func1 = (x: boolean): number =\u003e x ? 1 : 0\nconst func2 = (x: number): string =\u003e x \u003e 0 ? \"yay!\" : \"meh\"\nconst func3 = (x: string) =\u003e ({ result: x })\nconst func4 = (x: { result: string }): string =\u003e `Result: ${x.result}` \n\nconst chained = chain(func1, func2, func3, func4) // Typed as (x: boolean) =\u003e string\nconsole.log(chained(true)) // \"Result: yay!\"\n```\n\n## Install\n\nFor installation run:\n\n```bash\nyarn add @b00gizm/typed-chain\n```\n\nOr for npm:\n\n```bash\nnpm install --save @b00gizm/typed-chain\n```\n\n## Examples\n\n### Basic usage\n\n```typescript\nimport { chain } from '@b00gizm/typed-chain'\n\n// The output type of each function *MUST* match the input type of the next function\nconst func1 = (x: boolean): number =\u003e x ? 1 : 0\nconst func2 = (x: number): string =\u003e x \u003e 0 ? \"yay!\" : \"meh\"\nconst func3 = (x: string) =\u003e ({ result: x })\nconst func4 = (x: { result: string }): string =\u003e `Result: ${x.result}` \n\n// Chain functions together\nconst chained = chain(func1, func2, func3, func4) // Typed as (x: boolean) =\u003e string\n\n// Call the chain\nconst result = chained(true) // \"Result: yay!\"\n\n// It won't compile if functions are not compatible or in the wrong order\nchain(func1, func3, func2) // Error (number is not assignable to string)\n```\n\n### Usage for functions with multiple arguments\n\nIt is possible to chain functions with multiple arguments, for example if you want to pass a context object to each function. Everything after the first argument will be passed through to each function in the chain.\n\n```typescript\nimport { chain } from '@b00gizm/typed-chain'\n\nconst PREMIUM_DISCOUNT = 20\n\nconst discount = (\n  price: number,\n  context: { premiumUser: boolean },\n): number =\u003e (context.premiumUser ? price * (100-PREMIUM_DISCOUNT)/100 : price)\n\nconst message = (\n  price: number,\n  context: { premiumUser: boolean },\n): string =\u003e\n  context.premiumUser\n    ? `Special offer: $${price} (${PREMIUM_DISCOUNT}% discount)`\n    : `Price: $${price}`\n\nconst chained = chain(discount, message) // Typed as (price: number, context: { premiumUser: boolean }) =\u003e string\nconst result = chained(100, { premiumUser: true }) // \"Special offer: $80 (20% discount)\"\n```\n\nPlease note that there cannot be any side-effects when using this method, eg. any changes you make to a potential context object **will not be passed** through to the next function in the chain.\n\n### Asynchronous chains\n\nIt is also possible to chain asynchronous functions together using `asyncChain`. Here, the _awaited_ output type of each function must match the input type of the next function. Here is an asynchronous version of the previous example, where the discount percentage is asynchronously fetched from some API.\n\n```typescript\nimport { asyncChain } from '@b00gizm/typed-chain'\n\nconst discount = async (\n  price: number,\n  context: { premiumUser: boolean },\n): =\u003e {\n  if (context.premiumUser) {\n    // Asnychonously fetch discount percentage\n    const response = await fetch('/discounts')\n    const { percentage } = await response.json()\n\n    return {\n      price: (price * (100-percentage)/100), \n      discount: percentage\n    }\n  }\n\n  return { price, discount: 0 }\n}\n\nconst message = async (\n  priceInfo: { price: number, discount: number },\n  context: { premiumUser: boolean },\n): Promise\u003cstring\u003e =\u003e {\n  if (context.premiumUser) {\n    return `Special offer: $${priceInfo.price} (${priceInfo.discount} discount)`\n  }\n\n  return `Price: $${priceInfo.price}`\n}\n\nconst chained = asyncChain(discount, message) // Typed as (price: number, context: { premiumUser: boolean }) =\u003e Promise\u003cstring\u003e\nconst result = await chained(100, { premiumUser: true }) // \"Special offer: $80 (20% discount)\"\n```\n\nPlease note that every function in the chain **must be declared as `async`**. Mixing synchronous and asynchronous functions is not supported for the time being.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fb00gizm%2Ftyped-chain","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fb00gizm%2Ftyped-chain","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fb00gizm%2Ftyped-chain/lists"}