{"id":16688859,"url":"https://github.com/danieldietrich/typelevel","last_synced_at":"2025-07-24T03:01:51.047Z","repository":{"id":61509622,"uuid":"551956590","full_name":"danieldietrich/typelevel","owner":"danieldietrich","description":"Lift your code to the next level.","archived":false,"fork":false,"pushed_at":"2022-11-25T18:58:05.000Z","size":291,"stargazers_count":5,"open_issues_count":7,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-12T06:41:22.550Z","etag":null,"topics":[],"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/danieldietrich.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}},"created_at":"2022-10-15T13:34:35.000Z","updated_at":"2024-05-19T03:13:07.000Z","dependencies_parsed_at":"2022-10-19T22:30:26.948Z","dependency_job_id":null,"html_url":"https://github.com/danieldietrich/typelevel","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/danieldietrich/typelevel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danieldietrich%2Ftypelevel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danieldietrich%2Ftypelevel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danieldietrich%2Ftypelevel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danieldietrich%2Ftypelevel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danieldietrich","download_url":"https://codeload.github.com/danieldietrich/typelevel/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danieldietrich%2Ftypelevel/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265848013,"owners_count":23838180,"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-10-12T15:45:28.754Z","updated_at":"2025-07-24T03:01:50.926Z","avatar_url":"https://github.com/danieldietrich.png","language":"TypeScript","readme":"\u003cdiv id=\"typelevel-logo\" align=\"center\"\u003e\n  \u003cimg alt=\"TypeLevel Logo Dark Mode\" src=\"https://user-images.githubusercontent.com/743833/196892454-19e7eb18-7434-46de-a476-d39606507692.png#gh-dark-mode-only\" width=640\u003e\n  \u003cimg alt=\"TypeLevel Logo Light Mode\" src=\"https://user-images.githubusercontent.com/743833/196917074-f23107b9-c408-4267-9ab1-e0964fb576ba.png#gh-light-mode-only\" width=640\u003e\n  \u003ch3\u003e\n    Lift your code to the next level.\n  \u003c/h3\u003e\n\u003c/div\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\u003cdiv id=\"badges\" align=\"center\"\u003e\n\n[![npm version](https://img.shields.io/npm/v/typescript-typelevel?logo=npm\u0026style=flat-square)](https://www.npmjs.com/package/typescript-typelevel/)\n[![build](https://img.shields.io/github/workflow/status/danieldietrich/typelevel/Build/main?logo=github\u0026style=flat-square)](https://github.com/danieldietrich/typelevel/actions/workflows/build.yml)\n[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod\u0026style=flat-square)](https://gitpod.io/#https://github.com/danieldietrich/typelevel)\n\n\u003c/div\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\u003ctt\u003e**\u0026lt;TypeLevel\u003e**\u003c/tt\u003e pushes payload from the JavaScript runtime to the TypeScript compiler. The highly composable type level API gives us the superpower to free JS apps from unnecessary ballast.\n\nIdeally, types describe the domain, both structure and behavior. The latter is a challenge. There are not many major languages which are capable of describing behavior on the type level. TypeScript is different, it empowers us to perform algorithmic type transformations.\n\nTypeScript does not pretend anything how to use the types. This is where \u003ctt\u003e**\u0026lt;TypeLevel\u003e**\u003c/tt\u003e comes into play. \u003ctt\u003e**\u0026lt;TypeLevel\u003e**\u003c/tt\u003e is more than a toolkit of useful utility methods, it offers a **solution** that yields a **mental model** for **type level programming** in TypeScript.\n\n## Usage\n\nInstall \u003ctt\u003e**\u0026lt;TypeLevel\u003e**\u003c/tt\u003e\n\n```sh\nnpm i -D typescript-typelevel\n```\n\n## Features\n\n### Functions\n\n| Type                                               |\n| -------------------------------------------------- |\n| `Fn\u003cA extends any[] = any[], R extends any = any\u003e` | \n\n### Objects\n\n| Type                                     |\n| ---------------------------------------- |\n| `Obj`                                    |\n| `Keys\u003cT\u003e`                                |\n| `Values\u003cT\u003e`                              |\n| `Paths\u003cT\u003e`                               |\n| `Combine\u003cT\u003e`                             |\n| `Filter\u003cT, V, C extends boolean = true\u003e` |\n\n### Predicates\n\n| Type                                          |\n| --------------------------------------------- |\n| `And\u003cC1 extends boolean, C2 extends boolean\u003e` |\n| `Or\u003cC1 extends boolean, C2 extends boolean\u003e`  |\n| `Not\u003cC extends boolean\u003e`                      |\n| `Equals\u003cT1, T2\u003e`                              |\n| `Extends\u003cT1, T2\u003e`                             |\n| `Is\u003cT1, T2\u003e`                                  |\n| `IsIn\u003cT, U\u003e`                                  |\n| `IsEach\u003cT, U\u003e`                                |\n| `IsEmpty\u003cT\u003e`                                  |\n| `IsUniversal\u003cT\u003e`                              |\n\n### Utilities\n\n| Type                                   |\n| -------------------------------------- |\n| `TupleToIntersection\u003cT extends any[]\u003e` |\n| `TupleToUnion\u003cT extends any[]\u003e`        |\n| `UnionToIntersection\u003cU\u003e`               |\n| `UnionToTuple\u003cT\u003e` ⚠️                   |\n\n### Type Checker\n\n| Type                                                 |\n| ---------------------------------------------------- |\n| `Check\u003cT\u003e`                                           |\n| `CheckError\u003cMessage = any, Cause = any, Help = any\u003e` |\n| `CheckResult\u003cT, C extends Check\u003cT\u003e[], K extends PropertyKey = 'typelevel_error'\u003e` |\n\n## The Essence of TypeScript\n\nJavaScript (JS) is a structurally typed language. Informally, two types are assignable (read: considered \"equal\"), if they share the same properties. JS is dynamically typed, errors are reported at runtime.\n\nTypeScript (TS) adds a static type system on top of JS, we say TS is a superset of JS. In fact, the essence of TS's type system is very simple, it consits of a set of built-in types and operations for type composition.\n\n### Declaring types\n\n* `type` a type alias that does not change\n* `interface` a type that may be extended\n* `class` a JS class type\n* `enum` an enumeration\n\n### [Built-in types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html)\n\n* `{}` indexed arrays aka 'objects'\n* `[]` arrays and tuples\n* `() =\u003e T` functions\n* `string`, `number`, `boolean`, `bigint`, `symbol`, `undefined`, `null` primitive types\n* `'abc'`, `1`, `true`, ... literal types\n* `void` absence of any type\n* `any`, `unknown`, `never` universal types\n\n### Universal types\n\n`any` and `unknown` are both at the top of the type hierarchy, every type extends them. Informally, they can be seen as union of all possible types. However, technically they are no union types.\n\n`unknown` is the neutral element of the type intersection `\u0026` operation.\n\n```ts\nA \u0026 unknown = A\nA \u0026 any = any\n```\n\n`any` and `unknown` have different meanings. `any` is treated as any type to make the compiler happy at the cost of opting-out of type checking. `unknown` is similar to `any` while staying type-safe.\n\n`never` is at the bottom of the type hierarchy, it can be seen as subtype of all existing types, a type that will never occur.\n\n`never` is the empty union and the neutral element of the type union `|` operation.\n\n```ts\nA | never = A\n```\n\nHint on matching objects:\n\n* `Record\u003cPropertyType, unknown\u003e` matches indexed arrays\n* `Record\u003cPropertyType, any\u003e` matches all types with an index structure, like objects, arrays, functions, interfaces and classes\n\n### Composing Types\n\n[Union and intersection](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types):\n\n* `T | U` union type, neutral element `never` (the \"empty union\")\n* `T \u0026 U` intersection type, neutral element `unknown`\n\n[Derive types from types](https://www.typescriptlang.org/docs/handbook/2/types-from-types.html):\n\n* `T\u003cU\u003e` [generic type](https://www.typescriptlang.org/docs/handbook/2/generics.html)\n* `keyof T` [keyof operator](https://www.typescriptlang.org/docs/handbook/2/keyof-types.html)\n* `T['prop']` [indexed access type](https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html)\n* `` `..${T}..` ``\u003c/code\u003e [template literal type](https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html)\n* `{ [K in keyof T]: U }` [mapped type](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html)\n* `T extends U ? V : W` [conditional type](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html)\n* `T extends infer U ? V : W` [inferred type]()\n\n_Note: [`typeof`](https://www.typescriptlang.org/docs/handbook/2/typeof-types.html) was intentionally not mentioned because it does not operate on the type level._\n\n### Type Distribution\n\nOne of the most important concepts in TS is the [distribution of union types over conditional types](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types).\n\n_This [Stack Overflow answer](https://stackoverflow.com/questions/62084836/what-does-it-mean-for-a-type-to-distribute-over-unions) by [Karol Majewski\n](https://stackoverflow.com/users/10325032/karol-majewski) describes it best:_\n\n\u003e The term _distributive_ refers to how union types should be treated when subjected to type-level operations (such as `keyof` or mapped types).\n\u003e\n\u003e * **Non-distributive (default)** operations are applied to properties that exist on every member of the union.\n\u003e * **Distributive** operations are applied to _all members_ of the union separately.\n\u003e\n\u003e Let's use an example.\n\u003e\n\u003e ```ts\n\u003e type Fruit =\n\u003e   | { species: 'banana', curvature: number }\n\u003e   | { species: 'apple', color: string }\n\u003e ```\n\u003e\n\u003e Let's assume that, for some reason, you want to know all possible keys that can exist on a `Fruit`.\n\u003e\n\u003e **Non-distributive**\n\u003e\n\u003e Your intuition may tell you to do:\n\u003e\n\u003e ```ts\n\u003e type KeyOfFruit = keyof Fruit; // \"species\"\n\u003e ```\n\u003e\n\u003e However, this will give you only the properties that exist on every member of the union. In our example, `species` is the only common property shared by all `Fruit`.\n\u003e\n\u003e It's the same as applying `keyof` to the union of the two types.\n\u003e\n\u003e ```ts\n\u003e keyof ({ species: 'banana', curvature: number } | { species: 'apple', color: string })\n\u003e ```\n\u003e\n\u003e **Distributive**\n\u003e\n\u003e With distribution, the operation is not performed on _just_ the common properties. Instead, it is done on _every member of the union separately_. The results are then added together.\n\u003e\n\u003e ```ts\n\u003e type DistributedKeyOf\u003cT\u003e =\n\u003e   T extends any\n\u003e     ? keyof T\n\u003e     : never\n\u003e\n\u003e type KeyOfFruit = DistributedKeyOf\u003cFruit\u003e; // \"species\" | \"curvature\" | \"color\"\n\u003e ```\n\u003e\n\u003e In this case, TypeScript applied `keyof` to each member of the union, and summed the results.\n\u003e\n\u003e ```ts\n\u003e keyof { species: 'banana', curvature: number } | keyof { species: 'apple', color: string }\n\u003e ```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanieldietrich%2Ftypelevel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanieldietrich%2Ftypelevel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanieldietrich%2Ftypelevel/lists"}