{"id":21669357,"url":"https://github.com/attack-monkey/lean-functional-typescript","last_synced_at":"2026-04-29T13:37:10.121Z","repository":{"id":91874057,"uuid":"300398711","full_name":"attack-monkey/Lean-Functional-Typescript","owner":"attack-monkey","description":"A guide to Lean Functional Typescript","archived":false,"fork":false,"pushed_at":"2021-07-20T20:56:38.000Z","size":719,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-25T08:43:59.357Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"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/attack-monkey.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-10-01T19:24:06.000Z","updated_at":"2021-07-20T20:56:41.000Z","dependencies_parsed_at":null,"dependency_job_id":"1938fe58-299e-4a04-9c18-e8ebc4ffa85f","html_url":"https://github.com/attack-monkey/Lean-Functional-Typescript","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/attack-monkey%2FLean-Functional-Typescript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/attack-monkey%2FLean-Functional-Typescript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/attack-monkey%2FLean-Functional-Typescript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/attack-monkey%2FLean-Functional-Typescript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/attack-monkey","download_url":"https://codeload.github.com/attack-monkey/Lean-Functional-Typescript/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244570209,"owners_count":20474006,"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":[],"created_at":"2024-11-25T12:21:13.990Z","updated_at":"2026-04-29T13:37:10.114Z","avatar_url":"https://github.com/attack-monkey.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# A guide to Lean Functional Typescript\n\n**Lean** is the simple approach to functional programming (fp) in Typescript.\n\nLean is based on the ML family of languages, such as F#, ReScript, oCaml, and more.\n\nML based languages provide a simple way of writing safer code without the complexity of some other functional languages like Haskell.\n\nLean differs from say fp.ts which aligns many haskell-like features to Typescript, but at the cost of complexity and a steep learning curve.\n\nInstall\n=======\n\nThe Lean Prelude provides utilities such as **pattern matching** and **piping**, but much of Lean is actually just plain js / ts - library free.\n\nTo get going with Lean, download the **prelude**\n\n`npm i @attack-monkey/lean-f-ts-prelude`\n\n`import { pipe, match } from '@attack-monkey/lean-f-ts-prelude/dist/src'`\n\nIt works with both javascript and typescript...\n\nWe recommend typescript for the type-safety that it gives.\n\nWhy Lean?\n=========\n\nIf you are able to, check out **ReScript**, which is actually ML based JavaScript - It's light-weight and elegant.\n\nIf however, your organisation insists on using typescript ( or just javascript ), then Lean is for you.\n\nLean is simpler than the likes of fp.ts. It is more idiomatic to typescript, and so doesn't require stack of additional modules to get going.\n\nThere is no mention of Monads, Functors, or any other scary Haskell-like terms.\n\nLean also interconnects with the rest of the typescript functional eco-system seamlessly (See the section on Type-lifting).\n\nGetting Started - Pure Functions\n================================\n\nPure Functions are the building blocks of any functional programming. Pure Functions take in input and return output - without mutating anything.\n\nThis therefore enforces data that is immutable.\n\nWhenever they are passed the same set of inputs - they always return the same output.\n  \n**Single argument functions are known as unary functions**\n\n```typescript\n\nconst increment = (num: number) =\u003e num + 1\n\nconst a = 1\nconst b = increment(a) // a is still 1, b is 2\n\n```\n\n**Unary functions can be connected together easily to form more powerful functions**\n\n```typescript\n\nconst a = 1\nconst c = increment(increment(a)) // c is 3\n\n```\n\n**Pipes allow you to do the above in a much cleaner way**\n\nIn FP languages such as F# you can write the above as:\n\n```fsharp\n\nlet a = 1 // equivalent to js const\n\nlet c = a |\u003e increment |\u003e increment\n\n```\n\n\u003e `a` is piped into the `increment` function which is piped into the next `increment` function.\n\nand while there is not yet (though there is a proposal for this) a pipeline operator in js / ts, Lean provides `pipe` which can be used in a similar way.\n\n**A `pipe` is able to pipe a value through a series of functions**\n\n```typescript\n\nconst three = pipe(1)\n  .pipe(increment)\n  .pipe(increment)\n  .done()\n\n```\n\n**Most of the time in Lean, we use partial function syntax to write functions...**\n\nA partial function is a function that returns another function, and so on, until the full function is played out.\n\n```typescript\n\nconst add = (a: number) =\u003e (b: number) =\u003e a + b\n\nconst add3 = add(3)\nconst seven = add3(4)\n\n```\n\n**Which are easier to use in pipes than regular multi-argument functions**\n\n```typescript\n\nconst add = (a: number) =\u003e (b: number) =\u003e a + b\n\nconst seven = pipe(4).pipe(add(3)).done()\n\n```\n\n**Partials also provide a simple, powerful way of doing Dependency Injection**\n\nSee: https://github.com/attack-monkey/Lean-Functional-Typescript/blob/main/Dependency-Injection.md\n\n**Javscript multi-arguments are still useful - especially when dealing with optional parameters**\n\n```typescript\n\nconst myFunction = (a: number, b?: number) =\u003e a + ( b || 0 )\n\nconst a = myFunction(10) // 10\n\nconst a = myFunction(10, 10) // 20\n\n```\n\n**When dealing with many optional parameters it is also common to use objects and destructure patterns**\n\n```typescript\n\nconst showCat = (options: { isFluffy: boolean, likesToScratch: boolean, likesIceCream: boolean }) =\u003e { ... }\n\n```\n\n**Pure Functions can also be recursive and should be used in place of loops - because loops mutate values.**\n\nAn example of a recursive function\n\n```typescript\n\nconst sum = (numArr: number[], cursor = 0, ac = 0): number =\u003e\n    numArr.length - 1 === cursor\n        ? ac + numArr[cursor]\n        : sum(numArr, cursor + 1, ac + numArr[cursor])\n\nconsole.log(\n    sum([1, 4, 20])\n) // 25\n\n```\n\n\u003e Note: High levels of recursion in ts / js can lead to blowing the stack. A technique called trampolining is often used in high recursion code to address this. \n\n```typescript\n\ntype Fn = (...args: any[]) =\u003e any\n\nconst trampoline = (fn: Fn) =\u003e (...args: any[]) =\u003e {\n  let result = fn(...args)\n  while (typeof result === 'function') {\n    result = result()\n  }\n  return result\n}\n\ntype RecNumber = number | (() =\u003e RecNumber)\n    \nconst sumRec = (numArr: number[], cursor = 0, ac = 0): RecNumber =\u003e\n    numArr.length - 1 === cursor\n        ? ac + numArr[cursor]\n        : () =\u003e sumRec(numArr, cursor + 1, ac + numArr[cursor])\n    \nconst sum = trampoline(sumRec)\n\nconsole.log(\n    sum([1, 4, 20, 20, 80, 100])\n) // 225\n\n```\n\nCall Signatures\n===============\n\n**In Lean, the focus is on data that meets the call signature of the function.**\n\nFor example, the two functions below both work on the call signature of `number` therefore any `number` can be passed into these functions. There is no need for an object to be constructed from a class containing the `increment` and `decrement` method. There is no need to bind to an object's `this`\n\n```typescript\n\nconst increment = (a: number) =\u003e a + 1\n\nconst decrement = (a: number) =\u003e a - 1\n\n```\n\nIt is common to group functions that work on the same call signature into their own library object...\n\n```typescript\n\nconst increment = (a: number) =\u003e a + 1\n\nconst decrement = (a: number) =\u003e a - 1\n\nconst PureNumber = {\n  increment,\n  decrement\n}\n\nconst a = 0\n\nconst b = PureNumber.decrement(a) // -1\n\n```\n\nGrouping functions like this comes in very handy for functions like `map`, `filter`, and `reduce` which work differently depending on the call signature...\n\n```typescript\n\n\nconst myArray = ['apple', 'cider', 'vinegar']\n\nconst myRecord = {\n    a: 'cat',\n    b: 'dog',\n    c: 'monkey'\n}\n\npipe(myArray)\n  .pipe(Array_.map(item =\u003e item + '!!!'))\n  .pipe(Array_.filter(item =\u003e item !== 'vinegar!!!'))\n  .pipe(Array_.reduce((ac: string, cv: string) =\u003e ac + cv)('I like '))\n  .pipe(console.log)\n\npipe(myRecord)\n  .pipe(Record.map(item =\u003e item + '!!!'))\n  .pipe(Record.filter(item =\u003e item !== 'monkey!!!'))\n  .pipe(Record.reduce((ac: string, cv: string) =\u003e ac + cv)('hello '))\n  .pipe(console.log)\n\n```\n\n\u003e Note that `Record` and `Array_` are provided in the Prelude.\n\nType Lifting\n============\n\n\"Type lifting\" is when a normal value without methods is 'lifted' to a more powerful version that has methods associated with it.\n\nIn Javascript automatic Type Lifting occurs for most value types, for example:\n\n```typescript\n\n// 10 is a value with type of number\n10\n\n// 10 is also lifted to being an instance of Number which grants it methods.\n(10).toString()\n\n// 10 can also utilise the Number static methods...\nNumber.isInteger(10) // true\n// or\npipe(10)\n  .pipe(Number.isInteger)\n  .done()\n\n```\n\nAutomatic Type Lifting also occurs on arrays...\n\n```typescript\n// [1,2,3] is an array of numbers\n[1,2,3]\n\n\n// [1,2,3] is also lifted to being an instance of Array which grants it methods.\n[1,2,3]\n  .map(x =\u003e x +1)\n  .filter(x =\u003e x \u003e 1)\n\n```\n\nIn Lean we sparingly use Type Lifting, and tend to use piping for most things instead. This lets functions / static methods do the heavy lifting, rather than having to write classes representing Lifted Types that contain methods that are only usable in that given class.\n\nIn saying that, `pipe` is a lifted type that grants values the `pipe` method - so obviously they can be very useful ;)\n\nAnd as you can see above, `[1,2,3].map(x =\u003e x +1).filter(x =\u003e x \u003e 1)` is nice and succinct and still functional.\n\nType Lifting and other fp libraries\n===================================\n\nType Lifting essentially uses object-oriented programming to provide Lifted Types. It opens up a world of libraries such as:\n- Immutable.js for Immutable Data Structures\n- Rxjs for Asynchronous Functional Programming (Reactive Programming)\n- Fp.ts for a more Haskell-like fp experience.\n\nMutables\n========\n\nIn Js / Ts there are no shortage of ways to write mutable code.\nIn fp - mutating code is used very sparingly, and instead immutable patterns (like Pure-functions) are greatly encouraged.\n\nLean provides some safer utilities for managing mutability than the out-of-the-box approach.\n\n`Predictable.store`: Is a safe, powerful replacement for out-of-the-box variables, providing: \n- Safe dispatch of state (any state that comes out of the store is cloned from the store's state, rather than the state itself)\n- Predictable reciepts of mutable operations.\n- Safe predictable subscriptions for safe event-driven programming.\n\n\u003e https://gist.github.com/attack-monkey/4299da2cdc582d7cdd1b593b193f1b20\n\n`mutable`: is a part of the Lean prelude, and a safer utility than the out-of-the-box variable mutation, providing:\n- Safe dispatch of state (any state that comes out of the store is cloned from the store's state, rather than the state itself)\n- A simple, non event driven approach to mutability.\n\u003e https://github.com/attack-monkey/Lean-Functional-Typescript/blob/main/Mutable.md\n\n\nMutating Objects\n================\n\nIf you do have to mutate values in a normal Js / Ts way and that value is an object / array - then take **caution**:\n\nObject properties are just references to underlying values, and when you edit an object - you actually update the underlyng value that the Object property points to. That means that when you copy an Object, you just create a reference Object to the same underlying values. Update a property on one Object and you've just updated the same property on the other Object.\n\nLean provides the `clone` utility that deep clones an Object to create a completely new Object.\n\n```typescript\n\nconst a = {\n  prop1: \"hello world\"\n}\n\nconst b = clone(a)\nb.prop1 = \"goodbye world\"\nconsole.log(a.prop1) // \"hello world\" \u003c- Yay, we didn't mutate a when mutating b\n\n```\n\n\nAsync\n=====\n\nJavascript and Typescript already provide Promises that handle asynchronicity.\n\n`fetch` for example provides a promise as a response to reaching out and calling an outside api.\n\n```typescript\n\nfetch('https://jsonplaceholder.typicode.com/todos/1')\n    .then(response =\u003e response.json())\n    .then(handler)\n\n```\n\nInfact Promises can be thought of as `pipe` for asynchronous operations.\n\nJavascript and Typescript also provide async / await for handling asynchronicity.\n\n```typescript\n\nconst a = await fetch('https://jsonplaceholder.typicode.com/todos/1')\nhandler(a.json())\nfunction handler (a_json) {\n  ...\n}\n\n```\n\nParallels\n==============\n\n`Promise.all` provides a standard way of processing multiple promises at once...\n\n```typescript\n\nPromise.all([\n  promise1,\n  promise2\n]).then(handler)\n\n```\n\nPattern Matching\n================\n\nIn ML based functional languages like F#, ReScript, etc. most if / then / else style logic is handled through Pattern Matching.\n\nLean provides powerful pattern matching, both with structural matches and matching on variants.\n\nMatching using Variants\n=======================\n\nVariants are a way of encoding values that may be one of many types. Unlike the structural pattern matching used above, variants provide a light-weight way of passing around uncertainty, and then being able to match and unwrap a definite type later.\n\nHere we create a variant called Option.\n\nOption is a classic fp way of managing whether something is what we think it is or something else.\n\n\n```typescript\n\n// Create base types that encode values\ntype Some\u003cA\u003e = { t: \"Some\", v: A }\ntype None = {t: \"None\", v: undefined }\n\n// Create the variant type\ntype Option\u003cA\u003e = Some\u003cA\u003e | None\n\n// Create constructors that return the variant type\nconst Some = \u003cA\u003e(a: A): Option\u003cA\u003e =\u003e ({\n    t: \"Some\",\n    v: a\n})\n\nconst None = (a: any): Option\u003cany\u003e =\u003e ({\n    t: \"None\",\n    v: undefined\n})\n\n// Values can now be encoded as a variant\nconst cat = Some(\"cat\")\n\n// Now the variant can be handled by switching on the type (t).\n// Each case knows that since the type (t) is defined, the type of the value (v) is known. \nswitch (cat.t) {\n    case \"Some\": console.log(`hello ${cat.v}!!`); break;\n    case \"None\": console.log(\":(\"); break;\n    default: console.log(\":(\"); break;\n}\n\n```\n\nStructural Pattern Matching\n===========================\n\nHere it's possible to create a type that can be matched against at run-time, and based on that match, trigger a function.\n\n```typescript\n\nmatch('hello')\n  .with_($string, s =\u003e console.log(s + ' world'))\n  .otherwise(_ =\u003e console.log('unable to match'))\n  \n```\n\nPattern matching takes a value and matches it against a series of patterns.\nThe first pattern to match, fires the value (with type inferred from the pattern) into an accompanying function.\n\nSo... let's say we have `name`.\n\nWe could do something like...\n\n```typescript\n\nmatch(name)\n  .with_('garfield', matchedName =\u003e `${matchedName} is a cat`)\n  .with_('odie', matchedName =\u003e `${matchedName} is a dog`)\n  .otherwise(_ =\u003e console.log('unable to match'))\n\n\n```\n\nIn the above `matchedName` in both cases is inferred to be a string - even though `name` may be of unknown type.\nThat's because `matchedName` infers it's type from the pattern.\n\nBut Pattern Matching is far more powerful than that...\n\n### Partial Matching \u0026 Destructuring\n\nObjects and arrays can be matched against a partial object / array.\n\n```typescript\n\nconst a = {\n  name: {\n    first: 'johnny',\n    last: 'bravo'\n  }\n}\n\nmatch(a)\n  .with_({ name: { first: 'johnny'} }, _ =\u003e `matching on first name`)\n  .otherwise(_ =\u003e 'unable to match')\n\n\n```\n\nWhich is particularly useful when used in combination with destructuring\n\n```typescript\n\nmatch(a)\n  .with_({ name: { first: 'johnny'} }, ({ name: { first: b }}) =\u003e `Hey it's ${b}`)\n  .otherwise(_ =\u003e 'unable to match')\n```\n\n### Runtime Interfaces\n\nSpecial runtime interfaces can be used to match against in place of values...\n\nHere we use `$string` in place of the literal 'johnny'.\n\n```typescript\n\nconst $matchPattern = {\n  name: {\n    first: $string \n  }\n}\n\nmatch(a)\n  .with_($matchedPattern, ({ name: { first: b }}) =\u003e `${b} is a string`)\n  .otherwise(_ =\u003e 'unable to match')\n\n\n```\n\nIt's also good to point out that a runtime interface automatically binds the correct type to the interface, so `$string` is of type `string`. So when `a` is matched, it infers the type `{ name: { first: string }}`\n\nRuntime interfaces are powerful...\n\n```typescript\n\nconst a = [1, 2, 3]\n\nmatch(a)\n  .with_($array($number), a =\u003e `${a} is an array of numbers`)\n  .otherwise(_ =\u003e 'unable to match')\n\n\n```\n\n```typescript\n\nmatch(a)\n  .with_([1, $number, 3], ([_, b, __]) =\u003e `${b} is a number`)\n  .otherwise(_ =\u003e 'unable to match')\n\n```\n\n```typescript\n\nconst a = {\n  a: [1, 2],\n  b: [3, 3, 4],\n  c: [1, 5, 99]\n}\n\nmatch(a)\n  .with_($record($array($number)), a =\u003e `A record of arrays of numbers - whoa`)\n  .otherwise(_ =\u003e 'unable to match')\n\n\n```\n\n```typescript\n\nconst a = 'cat' as unknown\n\nconsole.log(\n  match(a)\n    .with_($lt(100), _ =\u003e `\u003c 100`),\n    .with_($gt(100), _ =\u003e `\u003e 100`),\n    .with_(100, _ =\u003e `its 100`),\n    .otherwise(_ =\u003e `no idea ... probably a cat`)\n)\n\n```\n\n```typescript\n\nconst a = 'cat' as string | number\n\nmatch(a)\n  .with_($union([$string, $number]), _ =\u003e `a is string | number`)\n  .otherwise(_ =\u003e 'unable to match')\n\n\n```\n\nRuntime interfaces include\n\n- `$string`\n- `$number`\n- `$int`\n- `$boolean`\n- `$array([])`\n- `$record()`\n- `$union([])`\n- `$unknown`\n- `$nothing` \u003c- Use this to match on undefined \u0026 null\n- `$lt`\n- `$gt`\n- `$lte`\n- `$gte`\n- `$encoded` \u003c- Use this to match on variants - eg. Option, Some, None\n\n## Roll your own Runtime Interfaces\n\n```typescript\n\nconst $even =\n  {\n    runtimeInterface: true,\n    test: (a: number) =\u003e a % 2 === 0\n  } as unknown as number\n\nconst $odd =\n  {\n    runtimeInterface: true,\n    test: (a: number) =\u003e a % 2 !== 0\n  } as unknown as number\n\nconsole.log(\n  match(101)\n    .with_($even, _ =\u003e `number is even`),\n    .with_($odd, _ =\u003e `number is odd`)\n    .otherwise(_ =\u003e 'unable to match')\n) // number is odd\n\n```\nA Runtime interface is an object with the property `runtimeInterface: true`.\nThis tells the `with_` function to treat the value as a Runtime Interface.\n\nPrimitive Runtime Interfaces have a `type` property, but more complex ones have a `test` function that determines whether a match is being made.\n\nIn both `$odd` and `$even` the subject is piped into the test function and a boolean is returned which determines whether or not the subject matches.\n\nNote that the Runtime Interface object is coerced into the expected type should the path match.\n\nSimple, Safe Fetch\n==================\n\n```typescript\n\nconst $validJson = {\n  userId: $number,\n  id: $number,\n  title: $string,\n  completed: $boolean\n}\n\nfetch('https://jsonplaceholder.typicode.com/todos/1')\n  .then(response =\u003e response.json())\n  .then(json =\u003e\n    match(json)\n      .with_($validJson, json =\u003e console.log(`yay - ${ json.title }`))\n      .otherwise(_ =\u003e console.log(`Unexpected JSON response from API`))\n\n  )\n\n```\n\nType-cirtainty\n==============\n\nPattern matching becomes more powerful when used to drive type-cirtainty.\nThe return value of pattern matching is often a `union` type or just plain `unknown`.\n\nInstead we can drive type-cirtainty by not returning a response to a variable at all.\nInstead we call a function passing in the value of cirtain-type from the inferred match.\n\nIn the below `personAction` only fires if `bob` matches `$person` so if `personAction` runs at all, then it is with type-cirtainty.\n\n```typescript\n\nconst $person = {\n  name: {\n    first: $string\n  }\n}\n\ntype Person = typeof $person\n\nconst personAction = (person: Person) =\u003e {\n  //this action runs with type cirtainty :D\n  console.log(`${person.name.first} is safe`)\n}\n\nfetchPerson(123).then(\n  person =\u003e match(person)\n    .with_($person, personAction /* this only runs if a match occurs */)\n    .otherwise(_ =\u003e console.log('not a person'))\n)\n\n```\n\nConclusion\n==========\n\n- Lean is heavily based on the ML family of languages but is idiomatic to Js / Ts.\n- Lean focusses on data.\n- Data has a particular type, and in order to be passed into a function, the type needs to match the call signature of the function.\n- Data is piped through functions to create data transformations.\n- Pure Functions take in data, and return new data without mutating the input or any other variables.\n- Pattern Matching is used in place of if / else / switch for more powerful and simpler logic handling.\n\nPrelude API\n===========\n\n### pattern match api\n\n**class** `Match`\n\n**methods of `Match`**\n\n`of`\n\n_Creates a Match chain. Usually `match` is used instead._\n\nEg. `Match.of('cat')`\n\n`with_`\n\n```typescript\n\nmatch('cat')\n  .with_($string, str =\u003e console.log(`The string is ${str}`))\n  .done()\n  \n```\n\n_Provides a matching arm, with the thing to match against and a function to call, should the match occur..._\n\n`done`\n\n_Executes the patternMatch. `done` must be called at the end of the chain, in order for the matching to execute._\n\n**function** `match`\n\n_Used in place of `PatternMatch.of`_\n\n**Runtime Interfaces**\n\n- $string\n- $array\n- $boolean\n- $gt\n- $lt\n- $gte\n- $lte\n- $literal\n- $nothing\n- $number\n- $int\n- $record\n- $union\n- $unknown\n- $encoded\n\n### pipe\n\n**class** `Pipe`\n\n**methods of `Pipe`** \n\n`of`\n\n_Creates a Pipeable value. `pipe` is usually used instead._\n\n`pipe`\n\n_pipes the previous result into a new function_\n\nEg. `pipe(10).pipe(a =\u003e console.log(a + 10))`\n\n`done`\n\n_Returns the final value._\n\n**function** `pipe`\n\n_Used in place of `Pipe.of`_\n\n### mutable\n\n**function** `mutable`\n\nSee docs above\n\n### Js / Ts Helpers\n\n**function** clone\n\n_function clone - makes a deep-clone of any array / object (dereferences the new object from the old)_\n\nEg. `const a = clone(b)`\n\n### Libraries\n\n**Array_** _See docs above_\n\n**Record** _See docs above_\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fattack-monkey%2Flean-functional-typescript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fattack-monkey%2Flean-functional-typescript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fattack-monkey%2Flean-functional-typescript/lists"}