{"id":22282039,"url":"https://github.com/clickbar/dot-diver","last_synced_at":"2025-07-02T02:02:57.353Z","repository":{"id":147934986,"uuid":"617126791","full_name":"clickbar/dot-diver","owner":"clickbar","description":"A lightweight, powerful, and dependency-free TypeScript utility library that provides types and functions to work with object paths in dot notation.","archived":false,"fork":false,"pushed_at":"2025-05-01T12:01:52.000Z","size":562,"stargazers_count":24,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-06-25T06:15:25.423Z","etag":null,"topics":["dot-notation","path","types","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/clickbar.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-03-21T18:50:04.000Z","updated_at":"2025-05-23T18:22:16.000Z","dependencies_parsed_at":null,"dependency_job_id":"f6ded7ff-b3ad-4a1d-bb43-ad4236592bf3","html_url":"https://github.com/clickbar/dot-diver","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/clickbar/dot-diver","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clickbar%2Fdot-diver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clickbar%2Fdot-diver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clickbar%2Fdot-diver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clickbar%2Fdot-diver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/clickbar","download_url":"https://codeload.github.com/clickbar/dot-diver/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clickbar%2Fdot-diver/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263025523,"owners_count":23401792,"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":["dot-notation","path","types","typescript"],"created_at":"2024-12-03T16:24:46.350Z","updated_at":"2025-07-02T02:02:57.326Z","avatar_url":"https://github.com/clickbar.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Dot Diver 🌊🔍\n\nA lightweight, powerful, dependency-free and heavily over engineered TypeScript utility library providing utility types and functions to work with object paths in dot notation.\n\nDot notation is a popular and convenient way to access deeply nested properties in objects. With Dot Diver, you can safely work with object paths in TypeScript projects, ensuring complete type safety and avoiding runtime errors.\n\nExample:\n\n```typescript\nimport { getByPath } from '@clickbar/dot-diver'\n\nconst object = {\n  a: 'Hello world',\n}\n\nconst result = getByPath(object, 'a') // result is 'Hello world'\n```\n\n\u003cbr\u003e\n\n## 🌟 Features\n\n- 🎯 Works with arrays, tuples, and objects\n- 🛡️ Works with readonly properties\n- ✅ Tests included\n- 🌀 Works with cyclic dependencies in types\n- 🚫 No dependencies\n- 🪶 Tiny footprint\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n## 📦 Installation\n\nInstall the package using your favorite package manager:\n\nnpm\n\n```sh\nnpm install -D @clickbar/dot-diver\n```\n\nyarn\n\n```sh\nyarn add -D @clickbar/dot-diver\n```\n\npnpm\n\n```sh\npnpm install -D @clickbar/dot-diver\n```\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n## 🚀 Usage\n\n### 🔎 `getByPath` and 🔏 `setByPath`\n\n\u003cbr\u003e\n\n```ts\nimport { getByPath, setByPath } from '@clickbar/dot-diver'\n\n// Define a sample object with nested properties\nconst object = {\n  a: 'hello',\n  b: {\n    c: 42,\n    d: {\n      e: 'world',\n    },\n  },\n  f: [{ g: 'array-item-1' }, { g: 'array-item-2' }],\n}\n\n// Example 1: Get a value by path\nconst value1 = getByPath(object, 'a') // Output: 'hello'\nconsole.log(value1)\n\nconst value2 = getByPath(object, 'b.c') // Output: 42\nconsole.log(value2)\n\nconst value3 = getByPath(object, 'b.d.e') // Output: 'world'\nconsole.log(value3)\n\nconst value4 = getByPath(object, 'f.0') // Output: { g: 'array-item-1' }\nconsole.log(value4)\n\nconst value5 = getByPath(object, 'f.1.g') // Output: 'array-item-2'\nconsole.log(value5)\n\n// Example 2: Set a value by path\nsetByPath(object, 'a', 'new hello')\nconsole.log(object.a) // Output: 'new hello'\n\nsetByPath(object, 'b.c', 100)\nconsole.log(object.b.c) // Output: 100\n\nsetByPath(object, 'b.d.e', 'new world')\nconsole.log(object.b.d.e) // Output: 'new world'\n\nsetByPath(object, 'f.0', { g: 'new array-item-1' })\nconsole.log(object.f[0]) // Output: { g: 'new array-item-1' }\n\nsetByPath(object, 'f.1.g', 'new array-item-2')\nconsole.log(object.f[1].g) // Output: 'new array-item-2'\n```\n\n\u003e [!NOTE]\n\u003e At the moment, we can not support object properties having a '.' in their name, since this would conflict with the dot notation traversal.\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n### 🛣️ Path and 🔖 GetPathValue\n\n\u003cbr\u003e\n\n```typescript\nimport type { Path, GetPathValue } from '@clickbar/dot-diver'\n\n// Define a sample object type with nested properties\ntype MyObjectType = {\n  a: string\n  b: {\n    c: number\n    d: {\n      e: boolean\n    }\n  }\n  f: [{ g: string }, { g: string }]\n}\n\n// Example 1: Using the Path type\ntype MyObjectPaths = Path\u003cMyObjectType\u003e\n\n// MyObjectPaths will be a union type representing all valid paths in dot notation:\n// 'a' | 'b' | 'f' | 'b.c' | 'b.d' | 'b.d.e' | 'f.0' | 'f.1' | 'f.0.g' | 'f.1.g'\n\n// Example 2: Using the GetPathValue type\ntype ValueAtPathA = GetPathValue\u003cMyObjectType, 'a'\u003e // Output: string\ntype ValueAtPathB_C = GetPathValue\u003cMyObjectType, 'b.c'\u003e // Output: number\ntype ValueAtPathB_D_E = GetPathValue\u003cMyObjectType, 'b.d.e'\u003e // Output: boolean\ntype ValueAtPathF_0 = GetPathValue\u003cMyObjectType, 'f.0'\u003e // Output: { g: string }\ntype ValueAtPathF_0_G = GetPathValue\u003cMyObjectType, 'f.0.g'\u003e // Output: string\n```\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n### 🔄 Objects with cyclic dependency\n\n\u003cbr\u003e\n\n```typescript\nimport type { Path, GetPathValue } from '@clickbar/dot-diver'\n\n// Define an object type with nested properties and a cyclic dependency\ntype Node = {\n  id: number\n  label: string\n  parent: Node\n  children: Node[]\n}\n\n// Example 1: Using the Path type with the default depth limit\ntype NodePathsDepth2 = Path\u003cNode\u003e // Depth limit of 2\n\n// NodePathsDepth2 will be a union type representing all valid paths in dot notation up to a depth of 2:\n// 'id' | 'label' | 'parent' | 'children' | 'parent.id' | 'parent.label' | 'parent.parent' | 'parent.children' | `parent.parent.${any}` | `parent.children.${any}` | `children.${number}` | `children.${number}.${any}`\n\n// Example 2: Using the Path type with a custom depth limit\ntype NodePathsDepth3 = Path\u003cNode, never, { depth: 3; onlyWritable: false }\u003e // Depth limit of 3\n\n// With a depth limit of 3, NodePathsDepth3 will be a union type representing all valid paths in dot notation up to a depth of 3:\n// 'id' | 'label' | 'parent' | 'children'\n// | 'parent.id' | 'parent.label' | 'parent.parent' | 'parent.children' | `parent.parent.parent'\n// | `parent.parent.parent' | 'parent.parent.children' | ... etc.\n```\n\nThe second parameter is an `offset`. You can provide a valid path to start the autocompletion from there.\\\nThis is used in `getByPath` and `setByPath` to provide autocompletion for the next levels, starting from the current path.\nWhen using `getByPath` and `setByPath`, the `Depth` parameter is the lookahead depth and not the max depth.\n\nThe default depth is currently **3**.\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n### ⚙️ Customizing the Depth Lookahead Limit\n\nYou can customize the set and get functions, by implementing your own variant and using the provided types.\\\n\nHere is an example where we customize the lookahead depth to 5:\n\n\u003cbr\u003e\n\n```typescript\nimport { getByPath, setByPath } from '@clickbar/dot-diver'\n\nimport type { Path, SearchableObject, GetPathValue, SetPathValue } from '@clickbar/dot-diver'\n\nfunction getByPathDepth5\u003cT extends SearchableObject, P extends Path\u003cT, P, { depth: 5 }\u003e \u0026 string\u003e(\n  object: T,\n  path: P,\n): GetPathValue\u003cT, P\u003e {\n  return getByPath(object, path) as GetPathValue\u003cT, P\u003e\n}\n\nfunction setByPathDepth5\u003c\n  T extends SearchableObject,\n  P extends Path\u003cT, P, { onlyWriteable: true; depth: 5 }\u003e \u0026 string,\n\u003e(object: T, path: P, value: SetPathValue\u003cT, P\u003e): void {\n  setByPath(object, path, value as SetPathValue\u003cT, P\u003e)\n}\n\nexport { getByPathDepth5 as getByPath, setByPathDepth5 as setByPath }\n```\n\nThe intersection between `Path\u003cT, P, { depth: 5 }\u003e` and `string` is necessary for TypeScript to successfully narrow down the type of `P` based on the user-provided `path` input.\nWithout the intersection, the `path` would just be of type `Path\u003cT, P, { depth: 5 }\u003e` and `PathValueEntry` would be a union of all possible return types.\nBy using the intersection, TypeScript is forced to apply the `Path` constraints and infer the type from the provided user input.\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n## ❓ FAQ\n\n### ❗ Why are my paths truncated in a object with index signature?\n\nPaths get truncated, if they are unioned with a string. E.g. `keyof T | string`.\\\nThis should only happen in rare cases for objects looking like this:\n\n```typescript\ntype TestType = {\n  a: string\n  b: string\n  [key: string]: string\n}\n```\n\nIf your object has nested properties, for example looking like this:\n\n```typescript\ntype TestType = {\n  a: string\n  b: {\n    c: string\n  }\n  [key: string]: string\n}\n```\n\nYou will get autocompletion again, as soon as you typed the path to the nested object, e.g. `b.`.\n\n\u003cbr\u003e\n\n### ❗ Why are my paths truncated inside an array?\n\nYour paths are not truncated. TypeScript will still validate them.\nSome IDEs have problems with displaying `children.${number}` paths.\nIf you can, define the array as an tuple. This will include all paths in the autocompletion.\n\n\u003cbr\u003e\n\n### ❗ I get the error \"Type instantiation is excessively deep and possibly infinite.ts(2589)\"\n\nThis happens if TypeScript reaches its maximum depth limit. This library should prevent this, but it can still happen if a object has a lot of cyclic dependencies.\\\nFor example:\n\n```typescript\ntype TestType = {\n  a: TestType\n  b: [TestType]\n  c: TestType[]\n  d: {\n    e: TestType\n  }\n  f: TestType\n}\n```\n\nYou can try to decrease the lookahead depth of the autocompletion by reimplementing the `getByPath` and `setByPath` functions.\nSee [this section](#%EF%B8%8F-customizing-the-depth-lookahead-limit).\n\n\u003cbr\u003e\n\n## 👨‍💻 Contributing\n\nIf you would like to contribute to Dot Diver, feel free to fork the repository, make changes, and submit a pull request. We appreciate any help and feedback.\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for more information.\n\n\u003cbr\u003e\n\n## 🔒 Security Vulnerabilities\n\nPlease see [SECURITY](SECURITY.md) for details.\n\n\u003cbr\u003e\n\n## 📄 License\n\nDot Diver is licensed under the [MIT License](LICENSE.md).\n\n\u003cbr\u003e\n\n🎉 Happy diving! 🌊\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclickbar%2Fdot-diver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclickbar%2Fdot-diver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclickbar%2Fdot-diver/lists"}