{"id":15449078,"url":"https://github.com/hazae41/integers","last_synced_at":"2025-07-22T21:05:51.261Z","repository":{"id":163538855,"uuid":"639015636","full_name":"hazae41/integers","owner":"hazae41","description":"Statically typed integer arithmetic (experimental)","archived":false,"fork":false,"pushed_at":"2023-05-10T15:37:59.000Z","size":2335,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-13T16:09:41.431Z","etag":null,"topics":["arithmetic","compile-time","integers","numbers","typed","typescript"],"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/hazae41.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":["hazae41"],"patreon":"hazae41"}},"created_at":"2023-05-10T15:19:28.000Z","updated_at":"2023-05-15T08:21:49.000Z","dependencies_parsed_at":null,"dependency_job_id":"4c2f9ddb-c209-4a20-bcdf-cff4d85db106","html_url":"https://github.com/hazae41/integers","commit_stats":{"total_commits":4,"total_committers":1,"mean_commits":4.0,"dds":0.0,"last_synced_commit":"7d7632b6deefca23d924e8e9eb1f36019987ad77"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hazae41/integers","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazae41%2Fintegers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazae41%2Fintegers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazae41%2Fintegers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazae41%2Fintegers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hazae41","download_url":"https://codeload.github.com/hazae41/integers/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazae41%2Fintegers/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266572501,"owners_count":23950031,"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-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"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":["arithmetic","compile-time","integers","numbers","typed","typescript"],"created_at":"2024-10-01T20:42:41.109Z","updated_at":"2025-07-22T21:05:51.235Z","avatar_url":"https://github.com/hazae41.png","language":"TypeScript","funding_links":["https://github.com/sponsors/hazae41","https://patreon.com/hazae41"],"categories":[],"sub_categories":[],"readme":"# Integers\n\nStatically typed integer arithmetic (experimental)\n\n```tsx\ntype X = Add\u003c32_000, 32_123\u003e // 64_123\n\ntype Y = Subtract\u003cX, 64_000\u003e // 123\n\ntype P = IsGreater\u003c1_001, 1_000\u003e // true\n```\n\n```tsx\nconst x: 64_123 = add(32_000, 32_123)\n\nconst y: 123 = subtract(x, 64_000)\n\nconst p: true = greater(1_001, 1_000)\n```\n\n## Summary\n\nIt can type check numbers fast, up to 2**16 (=65_536), but the compiler will sometimes yell at you, especially when both the left-hand and right-hand sides are generic\n\n## Benefits and drawbacks\n- Fast type checking\n- Add and subtract big numbers up to 2**16 (= 65_536) (it can be increased but bundling will be slower)\n- Boolean inequalities\n- Slow bundling (~10 seconds)\n- The compiler will sometimes yell at you\n\n## Inequalities\n\nSeveral ways to attempt inequalities type checking, unfortunately none of them are ready for production\n\n### Nevering\n\n- Fast type checking\n- You need to have the left-hand side type to compare\n- The compiler will sometimes yell at you\n\n```tsx\nexport type Greater\u003cX extends number, Y extends number\u003e =\n  IsGreater\u003cX, Y\u003e extends true ? X : never\n\nexport type Less\u003cX extends number, Y extends number\u003e =\n  IsLess\u003cX, Y\u003e extends true ? X : never\n\nexport type GreaterOrEquals\u003cX extends number, Y extends number\u003e =\n  IsGreaterOrEquals\u003cX, Y\u003e extends true ? X : never\n\nexport type LessOrEquals\u003cX extends number, Y extends number\u003e =\n  IsLessOrEquals\u003cX, Y\u003e extends true ? X : never\n\nfunction increment\u003cX extends number\u003e(x: GreaterOrEquals\u003cX, 100\u003e) {\n  return add(x, 1)\n}\n\nincrement(150) // 151\n```\n\n### Remapping\n\n- Elegant, you can just use `Greater\u003c100\u003e` to only accept numbers `\u003e100`\n- Painfully slowwwwwwww type checking even on expensive computer\n\n```tsx\nexport type Greater\u003cT extends number\u003e = Exclude\u003ckeyof { [P in keyof Increment as IsGreater\u003cP, T\u003e extends true ? P : never]: never }, string | symbol\u003e\n\nexport type GreaterOrEquals\u003cT extends number\u003e = Exclude\u003ckeyof { [P in keyof Increment as IsGreaterOrEquals\u003cP, T\u003e extends true ? P : never]: never }, string | symbol\u003e\n\nexport type Less\u003cT extends number\u003e = Exclude\u003ckeyof { [P in keyof Increment as IsLess\u003cP, T\u003e extends true ? P : never]: never }, string | symbol\u003e\n\nexport type LessOrEquals\u003cT extends number\u003e = Exclude\u003ckeyof { [P in keyof Increment as IsLessOrEquals\u003cP, T\u003e extends true ? P : never]: never }, string | symbol\u003e\n\nexport type Range\u003cMin extends number, Max extends number\u003e = Exclude\u003ckeyof { [P in keyof Increment as IsRange\u003cP, Min, Max\u003e extends true ? P : never]: never }, string | symbol\u003e\n\nfunction increment\u003cX extends number\u003e(x: X \u0026 Greater\u003c100\u003e) {\n  return add(x, 1)\n}\n\nconst x = increment(150) // Greater\u003c101\u003e\n```\n\n### Opaque type guarding\n\n- This is annoying to use\n- This doesn't solve anything \n- You still have to do runtime if-else branching\n\n```tsx\nexport type Greater\u003cT extends number\u003e = number \u0026 { __greater: T }\n\nexport type Less\u003cT extends number\u003e = number \u0026 { __less: T }\n\nexport type Range\u003cMin extends number, Max extends number\u003e = Greater\u003cMin\u003e \u0026 Less\u003cMax\u003e\n\nexport function greater\u003cY extends number\u003e(x: number, y: Y): x is Greater\u003cY\u003e {\n  return x \u003e y as any\n}\n\nexport function less\u003cY extends number\u003e(x: number, y: Y): x is Less\u003cY\u003e {\n  return x \u003c y as any\n}\n\nexport function greaterOrEquals\u003cY extends number\u003e(x: number, y: Y): x is GreaterOrEquals\u003cY\u003e {\n  return x \u003e= y as any\n}\n\nexport function lessOrEquals\u003cY extends number\u003e(x: number, y: Y): x is LessOrEquals\u003cY\u003e {\n  return x \u003c= y as any\n}\n\nfunction increment(x: Greater\u003c100\u003e) {\n  return add(x, 1)\n}\n\nconst x = 150\n\nif (greater(x, 100))\n  increment(x) // number\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhazae41%2Fintegers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhazae41%2Fintegers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhazae41%2Fintegers/lists"}