{"id":23289785,"url":"https://github.com/cmatosbc/tyrany","last_synced_at":"2026-02-26T23:31:17.367Z","repository":{"id":268478765,"uuid":"904483556","full_name":"cmatosbc/tyrany","owner":"cmatosbc","description":"Tyrannic and repressive Typescript custom utility types. Bold and useful types to solve common JS/TS issues and dilemmas.","archived":false,"fork":false,"pushed_at":"2024-12-19T09:55:10.000Z","size":116,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-26T12:36:06.417Z","etag":null,"topics":["object-type","ts","typescript","typescript-library","typescript-objects","typescript-types"],"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/cmatosbc.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-12-17T01:30:26.000Z","updated_at":"2025-06-06T22:02:29.000Z","dependencies_parsed_at":"2024-12-17T02:46:23.065Z","dependency_job_id":"70510260-17b4-4ab9-a517-f14274b29693","html_url":"https://github.com/cmatosbc/tyrany","commit_stats":null,"previous_names":["cmatosbc/tyrany"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/cmatosbc/tyrany","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmatosbc%2Ftyrany","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmatosbc%2Ftyrany/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmatosbc%2Ftyrany/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmatosbc%2Ftyrany/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cmatosbc","download_url":"https://codeload.github.com/cmatosbc/tyrany/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmatosbc%2Ftyrany/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29876911,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T22:37:10.609Z","status":"ssl_error","status_checked_at":"2026-02-26T22:37:09.019Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":["object-type","ts","typescript","typescript-library","typescript-objects","typescript-types"],"created_at":"2024-12-20T04:18:08.158Z","updated_at":"2026-02-26T23:31:17.350Z","avatar_url":"https://github.com/cmatosbc.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tyrany\n\n[![Node.js CI](https://github.com/cmatosbc/tyrany/actions/workflows/node.js.yml/badge.svg)](https://github.com/cmatosbc/tyrany/actions/workflows/node.js.yml)\n\nA comprehensive collection of TypeScript utility types designed to enhance your type-safe development experience. A despotic control over your code behavior, crushing any resistance or mischief from regular JS implementations.\n\n## Installation\n\n```bash\nnpm install tyrany\n# or\nyarn add tyrany\n# or\npnpm add tyrany\n```\n\n## Utility Types\n\n### DeepPartial\u003cT\u003e\nMakes all properties in a type optional recursively, including nested objects and arrays.\n\n```typescript\ninterface Config {\n  server: {\n    port: number;\n    host: string;\n    ssl: {\n      enabled: boolean;\n      cert: string;\n    };\n  };\n  database: {\n    url: string;\n    timeout: number;\n  };\n}\n\n// Partial configuration where any property can be omitted\ntype PartialConfig = DeepPartial\u003cConfig\u003e;\n\nconst config: PartialConfig = {\n  server: {\n    port: 3000,\n    // host and ssl can be omitted\n  },\n  // database can be omitted\n};\n```\n\n### DeepReadonly\u003cT\u003e\nMakes all properties in a type readonly recursively, including nested objects and arrays.\n\n```typescript\ninterface User {\n  id: number;\n  name: string;\n  settings: {\n    theme: string;\n    notifications: boolean;\n  };\n  posts: Array\u003c{\n    id: number;\n    title: string;\n  }\u003e;\n}\n\n// All properties become readonly, including nested objects\ntype ReadonlyUser = DeepReadonly\u003cUser\u003e;\n\nconst user: ReadonlyUser = {\n  id: 1,\n  name: \"John\",\n  settings: {\n    theme: \"dark\",\n    notifications: true\n  },\n  posts: [{ id: 1, title: \"Hello\" }]\n};\n\n// TypeScript Error: Cannot modify readonly property\nuser.settings.theme = \"light\"; // Error\nuser.posts[0].title = \"Updated\"; // Error\n```\n\n### Exact\u003cT\u003e\nEnsures that an object type only allows the exact properties defined, preventing excess properties.\n\n```typescript\ninterface UserInput {\n  name: string;\n  age: number;\n}\n\ntype ExactUserInput = Exact\u003cUserInput\u003e;\n\n// TypeScript Error: Object literal may only specify known properties\nconst input: ExactUserInput = {\n  name: \"John\",\n  age: 30,\n  extra: true // Error: excess property\n};\n```\n\n### ExtractArrayType\u003cT\u003e\nExtracts the type of elements from an array type.\n\n```typescript\ntype StringArray = string[];\ntype NumberArray = Array\u003cnumber\u003e;\ntype UserArray = Array\u003c{ id: number; name: string }\u003e;\n\ntype String = ExtractArrayType\u003cStringArray\u003e; // string\ntype Number = ExtractArrayType\u003cNumberArray\u003e; // number\ntype User = ExtractArrayType\u003cUserArray\u003e; // { id: number; name: string }\n\n// Practical example with mapped types\nfunction transformArray\u003cT\u003e(array: T[], transform: (item: ExtractArrayType\u003cT[]\u003e) =\u003e string): string[] {\n  return array.map(transform);\n}\n```\n\n### Mutable\u003cT\u003e\nRemoves readonly modifiers from all properties in a type.\n\n```typescript\ninterface ReadonlyUser {\n  readonly id: number;\n  readonly name: string;\n  readonly settings: readonly {\n    readonly theme: string;\n    readonly notifications: boolean;\n  };\n}\n\ntype MutableUser = Mutable\u003cReadonlyUser\u003e;\n\nconst user: MutableUser = {\n  id: 1,\n  name: \"John\",\n  settings: {\n    theme: \"dark\",\n    notifications: true\n  }\n};\n\n// Now properties can be modified\nuser.id = 2;\nuser.settings.theme = \"light\";\n```\n\n### NestedOmit\u003cT, K\u003e\nRemoves a property deeply from an object type and its nested objects.\n\n```typescript\ninterface ApiResponse {\n  id: string;\n  data: {\n    id: string;\n    user: {\n      id: string;\n      name: string;\n    };\n    metadata: {\n      id: string;\n      timestamp: number;\n    };\n  };\n}\n\n// Removes all 'id' properties at any level\ntype CleanResponse = NestedOmit\u003cApiResponse, 'id'\u003e;\n\n// Result:\n// {\n//   data: {\n//     user: {\n//       name: string;\n//     };\n//     metadata: {\n//       timestamp: number;\n//     };\n//   };\n// }\n```\n\n### NonNullable\u003cT\u003e\nRemoves null and undefined from object properties.\n\n```typescript\ninterface FormData {\n  name: string | null;\n  email: string | undefined;\n  age: number | null;\n  bio?: string;\n}\n\ntype RequiredFormData = NonNullable\u003cFormData\u003e;\n\n// Result:\n// {\n//   name: string;\n//   email: string;\n//   age: number;\n//   bio: string;\n// }\n```\n\n### Nullable\u003cT\u003e\nMakes all properties in a type nullable (null | undefined).\n\n```typescript\ninterface User {\n  id: number;\n  name: string;\n  email: string;\n}\n\ntype NullableUser = Nullable\u003cUser\u003e;\n\n// Useful for partial updates\nconst userUpdate: NullableUser = {\n  id: 1,\n  name: null, // Will clear the name\n  email: undefined // Will not update the email\n};\n```\n\n### Optional\u003cT\u003e\nMakes all properties in a type optional.\n\n```typescript\ninterface Product {\n  id: number;\n  name: string;\n  price: number;\n  description: string;\n  category: string;\n}\n\ntype ProductUpdate = Optional\u003cProduct\u003e;\n\n// All fields are optional\nconst update: ProductUpdate = {\n  price: 29.99,\n  description: \"Updated description\"\n  // Other fields can be omitted\n};\n```\n\n### PartialKeys\u003cT, K\u003e\nMakes specific keys of an object type optional while keeping others required.\n\n```typescript\ninterface Article {\n  id: number;\n  title: string;\n  content: string;\n  author: string;\n  tags: string[];\n}\n\n// Make only 'tags' and 'author' optional\ntype DraftArticle = PartialKeys\u003cArticle, 'tags' | 'author'\u003e;\n\nconst draft: DraftArticle = {\n  id: 1,\n  title: \"TypeScript Tips\",\n  content: \"...\",\n  // tags and author are optional\n};\n```\n\n### PathKeys\u003cT\u003e\nGets all possible dot-notation paths in an object type. Useful for type-safe access to nested object properties.\n\n```typescript\ninterface User {\n  name: string;\n  profile: {\n    age: number;\n    address: {\n      street: string;\n      city: string;\n      country: {\n        code: string;\n        name: string;\n      }\n    }\n  }\n}\n\ntype Paths = PathKeys\u003cUser\u003e;\n/* Result:\n  | 'name'\n  | 'profile'\n  | 'profile.age'\n  | 'profile.address'\n  | 'profile.address.street'\n  | 'profile.address.city'\n  | 'profile.address.country'\n  | 'profile.address.country.code'\n  | 'profile.address.country.name'\n*/\n\n// Can be used for type-safe object access utilities\nfunction get\u003cT, P extends PathKeys\u003cT\u003e\u003e(obj: T, path: P): any {\n  return path.split('.').reduce((acc, part) =\u003e acc[part], obj);\n}\n```\n\n### PickByType\u003cT, V\u003e\nConstructs a new type by picking properties from type `T` whose values are assignable to type `V`.\n\n```typescript\ninterface User {\n  id: number;\n  name: string;\n  isAdmin: boolean;\n  meta: {\n    lastLogin: Date;\n  };\n}\n\ntype StringProperties = PickByType\u003cUser, string\u003e;\n// Result: { name: string }\n\ntype NumberProperties = PickByType\u003cUser, number\u003e;\n// Result: { id: number }\n```\n\n### PickByValue\u003cT, V\u003e\nSimilar to PickByType but with more precise type matching, picks properties from type `T` whose values exactly match type `V`.\n\n```typescript\ninterface Config {\n  port: number;\n  host: string;\n  debug: boolean;\n  timeout: number;\n  version: string;\n}\n\ntype StringSettings = PickByValue\u003cConfig, string\u003e;\n// Result: { host: string; version: string }\n\ntype NumberSettings = PickByValue\u003cConfig, number\u003e;\n// Result: { port: number; timeout: number }\n```\n\n### PromiseType\u003cT\u003e\nExtracts the type that a Promise resolves to.\n\n```typescript\nasync function fetchUser() {\n  return { id: 1, name: \"John\" };\n}\n\ntype FetchUserPromise = ReturnType\u003ctypeof fetchUser\u003e;\ntype User = PromiseType\u003cFetchUserPromise\u003e;\n\n// Useful for API response handling\nasync function processUser(promise: Promise\u003cunknown\u003e) {\n  const user = await promise;\n  const typedUser = user as PromiseType\u003ctypeof promise\u003e;\n  // typedUser is now properly typed\n}\n```\n\n### RequireAtLeastOne\u003cT\u003e\nMakes all properties optional but requires at least one property to be present.\n\n```typescript\ninterface SearchCriteria {\n  name: string;\n  email: string;\n  phone: string;\n  id: number;\n}\n\ntype SearchQuery = RequireAtLeastOne\u003cSearchCriteria\u003e;\n\n// Valid queries\nconst byName: SearchQuery = { name: \"John\" };\nconst byEmailAndPhone: SearchQuery = { email: \"john@example.com\", phone: \"123456\" };\n\n// TypeScript Error: At least one property must be present\nconst empty: SearchQuery = {}; // Error\n```\n\n### Try\u003cT, E\u003e\nRepresents a value that can either be a successful result of type `T` or an error of type `E`. Useful for type-safe error handling.\n\n```typescript\nasync function fetchData(): Promise\u003cTry\u003cUser, Error\u003e\u003e {\n  try {\n    const user = await db.getUser(1);\n    return { success: true, value: user };\n  } catch (error) {\n    return { success: false, error: error as Error };\n  }\n}\n\nconst result = await fetchData();\nif (result.success) {\n  console.log(result.value.name); // Type-safe access to user properties\n} else {\n  console.error(result.error.message); // Type-safe access to error properties\n}\n```\n\n### UnionToArray\u003cT\u003e\nConverts a union type into an array type, useful for working with union types in a more familiar array format.\n\n```typescript\ntype Status = 'pending' | 'active' | 'completed';\ntype StatusArray = UnionToArray\u003cStatus\u003e;\n// Result: ('pending')[] | ('active')[] | ('completed')[]\n\ntype Numbers = 1 | 2 | 3;\ntype NumberArray = UnionToArray\u003cNumbers\u003e;\n// Result: (1)[] | (2)[] | (3)[]\n\n// Useful for type-safe array operations\nconst statuses: StatusArray = ['active'];\nconst numbers: NumberArray = [1, 1, 1];\n```\n\n### UnionToIntersection\u003cT\u003e\nConverts a union type to an intersection type.\n\n```typescript\ntype User = { id: number; name: string };\ntype Timestamps = { createdAt: Date; updatedAt: Date };\ntype Metadata = { version: number; isActive: boolean };\n\ntype UserUnion = User | Timestamps | Metadata;\ntype FullUser = UnionToIntersection\u003cUserUnion\u003e;\n\n// Result:\n// {\n//   id: number;\n//   name: string;\n//   createdAt: Date;\n//   updatedAt: Date;\n//   version: number;\n//   isActive: boolean;\n// }\n```\n\n### AsyncReturnType\u003cT\u003e\nExtracts the return type of an async function, removing the Promise wrapper.\n\n```typescript\nasync function fetchUser() {\n  return {\n    id: 1,\n    name: 'John',\n    roles: ['admin']\n  };\n}\n\ntype User = AsyncReturnType\u003ctypeof fetchUser\u003e; \n// Result: { id: number; name: string; roles: string[]; }\n\nasync function getData(): Promise\u003cstring | number\u003e {\n  return 42;\n}\n\ntype Data = AsyncReturnType\u003ctypeof getData\u003e;\n// Result: string | number\n```\n\n### IntersectKeys\u003cT, U\u003e\nExtracts the common keys between two types.\n\n```typescript\ninterface User {\n  id: number;\n  name: string;\n  email: string;\n}\n\ninterface Employee {\n  id: string;\n  name: number;\n  department: string;\n}\n\n// Get common keys between User and Employee\ntype CommonKeys = IntersectKeys\u003cUser, Employee\u003e;\n// Result: 'id' | 'name'\n```\n\n### DeepFreeze\u003cT\u003e\nMakes all properties in a type deeply readonly, including nested objects and arrays. This is similar to DeepReadonly but specifically designed for creating immutable data structures.\n\n```typescript\ninterface User {\n  name: string;\n  settings: {\n    theme: string;\n    notifications: {\n      email: boolean;\n      push: boolean;\n    };\n  };\n  tags: string[];\n}\n\n// Create an immutable user type\ntype FrozenUser = DeepFreeze\u003cUser\u003e;\n\nconst user: FrozenUser = {\n  name: 'John',\n  settings: {\n    theme: 'dark',\n    notifications: {\n      email: true,\n      push: false,\n    },\n  },\n  tags: ['admin', 'user'],\n};\n\n// These will cause TypeScript errors:\nuser.name = 'Jane';              // Error\nuser.settings.theme = 'light';   // Error\nuser.tags.push('guest');         // Error\n```\n\n### Diff\u003cT, U\u003e\nComputes the difference between two types `T` and `U`, excluding properties of type `U` from type `T`.\n\n```typescript\n// Given types\ninterface A {\n  x: number;\n  y: string;\n}\n\ninterface B {\n  y: string;\n}\n\n// Resulting type will be { x: number; }\ntype Result = Diff\u003cA, B\u003e;\n```\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## License\n\nMIT License - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmatosbc%2Ftyrany","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcmatosbc%2Ftyrany","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmatosbc%2Ftyrany/lists"}