New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More β†’
Socket
Sign inDemoInstall
Socket

@clickbar/dot-diver

Package Overview
Dependencies
Maintainers
0
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@clickbar/dot-diver - npm Package Compare versions

Comparing version 1.0.6 to 2.0.0

225

dist/index.d.ts

@@ -0,1 +1,22 @@

declare type ArrayIsReadonlyArray<T> = T extends unknown[] ? false : true;
/**
* PathConfig is a configuration object that can be used to configure the behavior of the path function.
*
* @property onlyWriteable - If true, only writeable properties are returned
* @property depth - The maximum depth the path function should traverse
*/
declare interface BasePathConfig {
depth: number;
onlyWriteable: boolean;
}
/**
* Returns the substring between the last and second last occurrence of V in T.
* @example
* BeforeLast<'a.b.c.d', '.'> // 'c'
* BeforeLast<'a.b.c.d.e', '.'> // 'd'
*/
declare type BeforeLast<T extends string, V extends string | number> = T extends string ? T extends `${infer H}${V}${infer R}` ? R extends `${string}${V}${string}` ? `${H}${V}${BeforeLast<R, V>}` : H : T : never;
declare type BuildTuple<L extends number, T extends unknown[] = []> = T extends {

@@ -5,2 +26,15 @@ length: L;

/**
*
* CircularConstraintPathHelper allows us to use Path as a cyclic constraint for a generic parameter. e.g.
* function foo<T, P extends CircularConstraintPathHelper<T, 3, [P]>>(...)
*
* This allows us to use the given path as the offset parameter for the path type.
*
* @typeParam T - Type to traverse
* @typeParam P - Should be a tuple with the path to traverse from as its only element, e.g. [P]
* @typeParam Config - Configuration object
*/
declare type CircularConstraintPathHelper<T, Config extends BasePathConfig, P extends unknown[]> = P[number] extends never ? SimplePath<T, Config> : P[number] extends infer PV ? PV extends string | number ? PathWithOffset<T, Config, PV> : SimplePath<T, Config> : SimplePath<T, Config>;
declare type ExcludeNullUndefined<T> = Exclude<T, null | undefined>;

@@ -10,9 +44,16 @@

declare type GetArrayElement<T> = T extends (infer U)[] ? U : never;
/**
* Checks if a given value of type Type is an actual value of the type.
* E.g. if Type is number and Value is 5, it will return 5.
* If Type is number and Value is string, it will return Default.
* If Type is number and Value is number, it will return Default.
*/
declare type GetActualValue<Type, Value, Default> = [Value] extends [Type] ? [Type] extends [Value] ? Default : Value : Default;
declare type GetArrayPaths<T, DepthCarry extends unknown[]> = `${number}.${Path_2<GetArrayElement<T>, DepthCarry>}`;
declare type GetArrayElement<T> = T extends readonly (infer U)[] ? U : never;
declare type GetArrayPaths<T, DepthCarry extends unknown[], Config extends BasePathConfig> = (Config['onlyWriteable'] extends true ? ArrayIsReadonlyArray<T> extends true ? never : number | `${number}` : number | `${number}`) | `${number}.${TraversalGate<GetArrayElement<T>, DepthCarry, Config>}`;
/**
* Retrieves a value from an object by dot notation. The value is received by optional chaining,
* therefore this function returns undefined if an intermediate property is undefined.
* Retrieves a value from an object by dot notation
*

@@ -23,18 +64,30 @@ * @param object - object to get value from

* @privateRemarks
* The intersection between PathEntry<T, 10> and string is necessary for TypeScript to successfully narrow down the type of P based on the user-provided path input.
* Without the intersection, the path would just be of type PathEntry<T, 10> and PathValueEntry would be a union of all possible return types.
* By using the intersection, TypeScript is forced to apply the PathEntry constraints and infer the type from the provided user input.
* The intersection between Path<T, P> and string is necessary for TypeScript to successfully narrow down the type of P based on the user-provided path input.
* Without the intersection, the path would just be of type Path<T, P> and PathValue would be a union of all possible return types.
* By using the intersection, TypeScript is forced to apply the Path constraints and infer the type from the provided user input.
*/
export declare function getByPath<T extends SearchableObject, P extends Path<T> & string>(object: T, path: P): PathValue<T, P>;
export declare function getByPath<T extends SearchableObject, P extends '' | Path<T, P>>(object: T, path: P & string): GetPathValue<T, P>;
declare type GetRecordPaths<T, DepthCarry extends unknown[], K extends keyof T = keyof T> = K extends keyof T ? RemoveInvalidDotPathKeys<K> | `${RemoveInvalidDotPathKeys<K>}.${Path_2<T[K], DepthCarry>}` : never;
declare interface GetByPathConfig extends BasePathConfig {
depth: 3;
onlyWriteable: false;
}
declare type GetTuplePaths<T extends unknown[], DepthCarry extends unknown[]> = NumbersToZero<T, DepthCarry> extends infer R ? R extends number ? R | `${R}.${Path_2<TupleElement<T, R>, DepthCarry>}` : never : never;
declare interface GetByPathValuePathConfig extends BasePathConfig {
noUncheckedUnionAccess: true;
noUncheckedIndexAccess: true;
noUncheckedOptionalAccess: true;
}
declare type GetValidIndexSignature<T> = Exclude<keyof T, symbol> extends infer K ? K extends string | number ? K : never : never;
declare type GetObjectPaths<T, DepthCarry extends unknown[], Config extends BasePathConfig> = (Config['onlyWriteable'] extends true ? RemoveInvalidDotPathKeys<keyof RemoveReadonlyProperties<T>> : RemoveInvalidDotPathKeys<keyof T>) | (keyof T extends infer K ? K extends keyof T ? `${RemoveInvalidDotPathKeys<K>}.${TraversalGate<T[K], DepthCarry, Config>}` : never : never);
export declare type GetPathValue<T, P extends string | number> = PathValue<T, P, GetByPathValuePathConfig>;
declare type GetTuplePaths<T, DepthCarry extends unknown[], Config extends BasePathConfig> = Extract<keyof T, `${number}`> extends infer P ? P extends `${infer PV extends number}` ? (Config['onlyWriteable'] extends true ? ArrayIsReadonlyArray<T> extends true ? never : PV : PV) | `${PV}.${TraversalGate<TupleElement<T, PV>, DepthCarry, Config>}` : never : never;
declare type GetValidIndexSignature<T> = Exclude<keyof T, symbol> extends infer K ? (K extends string | number ? K : never) : never;
declare type HasIndexSignature<T> = string extends keyof T ? true : number extends keyof T ? true : symbol extends keyof T ? true : false;
/**
* check if a type is any
* @link https://stackoverflow.com/a/49928360/1490091

@@ -44,16 +97,22 @@ */

declare type IsArray<T> = T extends any[] ? true : false;
declare type IsArray<T> = T extends readonly any[] ? true : false;
declare type IsEmptyArray<T> = T extends [] ? true : false;
declare type IsEmptyArray<T> = T extends readonly [] ? true : false;
/**
* Check if two types are equal
* from type-fest
* @see https://github.com/sindresorhus/type-fest/blob/fa1c3f3cf49c4d5aae9da47c04320d1934cb2f9b/source/is-equal.d.ts#L29
*/
export declare type IsEqual<A, B> = (<G>() => G extends A ? 1 : 2) extends <G>() => G extends B ? 1 : 2 ? true : false;
declare type IsNever<T> = [T] extends [never] ? true : false;
declare type IsNullableOrUndefineable<T> = null extends T ? true : undefined extends T ? true : false;
declare type IsNullableOrUndefinable<T> = null extends T ? true : undefined extends T ? true : false;
declare type IsPrimitive<T> = T extends string | number | boolean | bigint | symbol | undefined | null ? true : false;
declare type IsTuple<T> = T extends [any, ...any[]] ? true : false;
declare type IsTuple<T> = T extends readonly [unknown, ...unknown[]] ? true : false;
/**
* check if a type is unknown
* @link https://github.com/sindresorhus/type-fest

@@ -63,18 +122,38 @@ */

declare type MinusOne<N extends unknown[]> = N extends [...infer U, unknown] ? U : never;
declare type MinusOne<N extends unknown[]> = N extends [...infer U, unknown] ? U : [];
declare type NumbersToZero<IterationCarry extends unknown[], DepthCarry extends unknown[]> = TupleLength<DepthCarry> extends 0 ? any : TupleLength<IterationCarry> extends 0 ? never : NumbersToZero<MinusOne<IterationCarry>, MinusOne<DepthCarry>> | TupleLength<MinusOne<IterationCarry>>;
/**
* Path returns all paths in the given type and returns them until it reaches its max depth.
*
* It uses the given path as the offset to start the traversal from.
*
* @typeParam T - Type to traverse
* @typeParam Offset - Path to start the traversal from
* @typeParam Config - Configuration object
*
*/
export declare type Path<T, Offset = never, Config extends Partial<BasePathConfig> = GetByPathConfig> = CircularConstraintPathHelper<T, PathConfig<Config>, [Offset]>;
export declare type Path<T, Depth extends number = 10> = Path_2<T, BuildTuple<Depth>>;
declare type PathConfig<Config extends Partial<BasePathConfig>> = {
depth: GetActualValue<number, Config['depth'], 3>;
onlyWriteable: GetActualValue<boolean, Config['onlyWriteable'], false>;
};
declare type Path_2<T, DepthCarry extends unknown[]> = TupleLength<DepthCarry> extends 0 ? IsPrimitive<T> extends true ? never : any : T extends T ? PathStep<Writeable<ExcludeNullUndefined<T>>, MinusOne<DepthCarry>> : never;
export declare type PathValue<T, P extends string | number, Config extends ValueBasePathConfig> = P extends '' ? T : ValueTraversalGate<T, `${P}`, BuildTuple<40>, Config>;
declare type PathStep<T, Depth extends unknown[]> = IsAny<T> extends true ? string : IsUnknown<T> extends true ? never : IsPrimitive<T> extends true ? never : IsTuple<T> extends true ? T extends unknown[] ? GetTuplePaths<T, Depth> : never : IsArray<T> extends true ? (IsEmptyArray<T> extends true ? never : number) | GetArrayPaths<T, Depth> : HasIndexSignature<T> extends true ? GetValidIndexSignature<T> | GetRecordPaths<RemoveIndexSignature<T>, Depth> : GetRecordPaths<T, Depth>;
/**
* Similar to SimplePath, PathWithOffset return all paths in the given type and returns them until it reaches its max depth.
*
* The difference is that PathWithOffset allows to specify an offset to start the traversal from. It will start the traversal
* from the last parent at the given offset.
*
* a.b.c.d
* ^- return possible paths from here
*
* @typeParam T - Type to traverse
* @typeParam Config - Configuration object
* @typeParam Offset - Offset path
*/
declare type PathWithOffset<T, Config extends BasePathConfig, Offset extends string | number> = IsAny<Offset> extends true ? SimplePath<T, Config> : IsNever<Offset> extends true ? SimplePath<T, Config> : Offset extends `${string}.${string}` ? BeforeLast<Offset, '.'> extends infer H ? H extends string | number ? PathValue<T, H, GetByPathValuePathConfig> extends infer V ? IsNever<V> extends true ? SimplePath<T, Config> : `${H}.${SimplePath<V, Config>}` : SimplePath<T, Config> : never : never : SimplePath<T, Config>;
export declare type PathValue<T, P extends Path<T, Depth>, Depth extends number = 10> = PathValue_2<T, P, BuildTuple<Depth>>;
declare type PathValue_2<T, P, DepthCarry extends unknown[]> = TupleLength<DepthCarry> extends 0 ? IsPrimitive<T> extends true ? never : unknown : T extends T ? PathValueStep<Writeable<T>, P, MinusOne<DepthCarry>> : never;
declare type PathValueStep<T, P, DepthCarry extends unknown[]> = IsAny<T> extends true ? any : IsUnknown<T> extends true ? unknown : IsNullableOrUndefineable<T> extends true ? PathValue_2<ExcludeNullUndefined<T>, P, DepthCarry> | undefined : IsTuple<T> extends true ? P extends `${infer H}.${infer R}` ? PathValue_2<TupleElement<T, H>, R, DepthCarry> : TupleElement<T, P> : IsArray<T> extends true ? P extends `${infer _H}.${infer R}` ? PathValue_2<GetArrayElement<T>, R, DepthCarry> | undefined : GetArrayElement<T> | undefined : P extends `${infer H}.${infer R}` ? H extends keyof T ? PathValue_2<T[H], R, DepthCarry> | (HasIndexSignature<T> extends true ? undefined : never) : never : P extends keyof T ? T[P] | (HasIndexSignature<T> extends true ? undefined : never) : never;
declare type RemoveIndexSignature<T> = {

@@ -86,2 +165,10 @@ [K in keyof T as FilterIndexSignatureType<K>]: T[K];

declare type RemoveReadonlyProperties<T> = {
[K in keyof T as IsEqual<{
[k in K]: T[K];
}, {
readonly [k in K]: T[K];
}> extends false ? K : never]: T[K];
};
export declare type SearchableObject = object;

@@ -100,8 +187,66 @@

* @privateRemarks
* The intersection between PathEntry<T, 10> and string is necessary for TypeScript to successfully narrow down the type of P based on the user-provided path input.
* Without the intersection, the path would just be of type PathEntry<T, 10> and PathValueEntry would be a union of all possible return types.
* By using the intersection, TypeScript is forced to apply the PathEntry constraints and infer the type from the provided user input.
* The intersection between Path<T, P> and string is necessary for TypeScript to successfully narrow down the type of P based on the user-provided path input.
* Without the intersection, the path would just be of type Path<T, P> and PathValue would be a union of all possible return types.
* By using the intersection, TypeScript is forced to apply the Path constraints and infer the type from the provided user input.
*/
export declare function setByPath<T extends SearchableObject, P extends Path<T> & string, V extends PathValue<T, P>>(object: T, path: P, value: V): void;
export declare function setByPath<T extends SearchableObject, P extends Path<T, P, SetByPathConfig>>(object: T, path: P & string, value: SetPathValue<T, P>): void;
declare interface SetByPathConfig extends BasePathConfig {
depth: 3;
onlyWriteable: true;
}
declare interface SetByPathValuePathConfig extends BasePathConfig {
noUncheckedUnionAccess: false;
noUncheckedIndexAccess: false;
noUncheckedOptionalAccess: false;
}
export declare type SetPathValue<T, P extends string | number> = PathValue<T, P, SetByPathValuePathConfig>;
/**
* Simple Path return all paths in the given type and returns them until it reaches its max depth.
*
* @typeParam T - Type to traverse
* @typeParam Config - Configuration object
*/
declare type SimplePath<T, Config extends BasePathConfig> = TraversalGate<T, BuildTuple<Config['depth']>, Config>;
/**
* Checks for the remaining depth level and stops further traversal if necessary.
* Reduces the depth level by one if it traverse deeper.
* Removes problematic modifiers like readonly or undefined, null union types from it.
*
* @typeParam T - Type to check
* @typeParam DepthCarry - Tuple that is the size of the remaining depth level
* @typeParam Config - Configuration object
*/
declare type TraversalGate<T, DepthCarry extends unknown[], Config extends BasePathConfig> = T extends T ? IsAny<T> extends true ? string : IsUnknown<T> extends true ? never : IsPrimitive<T> extends true ? never : IsEmptyArray<T> extends true ? never : TupleLength<DepthCarry> extends 0 ? any : TraversalStep<ExcludeNullUndefined<T>, MinusOne<DepthCarry>, Config> : never;
/**
* Simple Path return all paths in the given type and returns them until it reaches its max depth.
* It works by recursively traversing each property of the current object until it reaches a primitive.
*
* Since Typescript could include cyclic types, e.g.
*
* type CyclicType = {
* cycle: CyclicType
* ...
* }
*
* we limit the depth. We can archive this by constructing a tuple the size of the max depth we want to go,
* and removing one element whenever we go one level deeper. As soon as the tuple is empty, we stop traversing,
*
*
*/
/**
* Checks the given generic Parameter T for its type
* and chooses an appropriate traversal strategy to find further paths.
*
* @typeParam T - Type to check
* @typeParam DepthCarry - Tuple that is the size of the remaining depth level
* @typeParam Config - Configuration object
*/
declare type TraversalStep<T, DepthCarry extends unknown[], Config extends BasePathConfig> = IsTuple<T> extends true ? GetTuplePaths<T, DepthCarry, Config> : IsArray<T> extends true ? GetArrayPaths<T, DepthCarry, Config> : HasIndexSignature<T> extends true ? GetValidIndexSignature<T> | GetObjectPaths<RemoveIndexSignature<T>, DepthCarry, Config> : GetObjectPaths<T, DepthCarry, Config>;
declare type TupleElement<T, N> = N extends keyof T ? T[N] : never;

@@ -113,2 +258,18 @@

/**
* ValuePathConfig is a configuration object that can be used to configure the behavior of the path function.
*
* @property onlyWriteable - If true, only writeable properties are returned
* @property depth - The maximum depth the path function should traverse
*/
declare interface ValueBasePathConfig {
noUncheckedUnionAccess: boolean;
noUncheckedIndexAccess: boolean;
noUncheckedOptionalAccess: boolean;
}
declare type ValueTraversalGate<T, P, DepthCarry extends unknown[], Config extends ValueBasePathConfig> = TupleLength<DepthCarry> extends 0 ? unknown : T extends T ? ValueTraversalStep<Writeable<T>, P, MinusOne<DepthCarry>, Config> : never;
declare type ValueTraversalStep<T, P, DepthCarry extends unknown[], Config extends ValueBasePathConfig> = IsAny<T> extends true ? any : IsUnknown<T> extends true ? unknown : IsNullableOrUndefinable<T> extends true ? ValueTraversalGate<ExcludeNullUndefined<T>, P, DepthCarry, Config> | Config['noUncheckedOptionalAccess'] extends true ? undefined : never : IsTuple<T> extends true ? P extends `${infer H extends number}.${infer R}` ? ValueTraversalGate<TupleElement<T, H>, R, DepthCarry, Config> : P extends `${infer K extends number}` ? TupleElement<T, K> : Config['noUncheckedUnionAccess'] extends true ? undefined : never : IsArray<T> extends true ? P extends `${infer _H extends number}.${infer R}` ? ValueTraversalGate<GetArrayElement<T>, R, DepthCarry, Config> | (Config['noUncheckedIndexAccess'] extends true ? undefined : never) : P extends `${infer _K extends number}` ? GetArrayElement<T> | (Config['noUncheckedIndexAccess'] extends true ? undefined : never) : Config['noUncheckedUnionAccess'] extends true ? undefined : never : P extends `${infer H}.${infer R}` ? H extends keyof T ? ValueTraversalGate<T[H], R, DepthCarry, Config> | (HasIndexSignature<T> extends true ? Config['noUncheckedIndexAccess'] extends true ? undefined : never : never) : Config['noUncheckedUnionAccess'] extends true ? undefined : never : P extends keyof T ? T[P] | (HasIndexSignature<T> extends true ? Config['noUncheckedIndexAccess'] extends true ? undefined : never : never) : Config['noUncheckedUnionAccess'] extends true ? undefined : never;
declare type Writeable<T> = {

@@ -115,0 +276,0 @@ -readonly [K in keyof T]: T[K];

32

dist/index.js

@@ -1,23 +0,23 @@

const i = Object.prototype.hasOwnProperty;
function a(o, n) {
return n.split(".").reduce((t, e) => {
if (!(typeof t != "object" || t === null || !i.call(t, e)))
return t[e];
const p = Object.prototype.hasOwnProperty;
function d(o) {
return o != null && (typeof o == "object" || typeof o == "function");
}
function c(o, e) {
return e === "" ? o : e.split(".").reduce((i, t) => {
if (!(!d(i) || i[t] === void 0 || !p.call(i, t)))
return i[t];
}, o);
}
function s(o, n) {
const r = o === null ? "null" : typeof o;
throw new TypeError(`Cannot create property '${n}' on ${r}`);
function f(o, e) {
const s = o === null ? "null" : typeof o;
throw new TypeError(`Cannot create property '${e}' on ${s}`);
}
function c(o, n, r) {
const t = n.split("."), e = t.pop();
if (e === void 0)
throw new Error("Path is empty");
const l = t.reduce((p, y) => ((typeof p != "object" || p === null || !i.call(p, y)) && s(p, y), p[y]), o);
(typeof l != "object" || l === null) && s(l, e), l[e] = r;
function u(o, e, s) {
const i = e.split("."), t = i.pop(), y = i.reduce((n, l) => (d(n) || f(n, l), n[l] === void 0 || n[l] === null || p.call(n, l) || f(n, l), n[l]), o);
y == null && f(y, t), y[t] = s;
}
export {
a as getByPath,
c as setByPath
c as getByPath,
u as setByPath
};
//# sourceMappingURL=index.js.map
{
"name": "@clickbar/dot-diver",
"version": "1.0.6",
"version": "2.0.0",
"description": "Types and utilities to access object properties by dot notation.",
"packageManager": "pnpm@8.8.0",
"types": "dist/index.d.ts",

@@ -41,18 +40,20 @@ "exports": {

"devDependencies": {
"@clickbar/eslint-config-typescript": "^9.0.1",
"eslint": "^8.51.0",
"prettier": "^3.0.3",
"typescript": "^5.2.2",
"vite": "^4.4.11",
"vite-plugin-dts": "^3.6.0",
"vitest": "^0.34.6"
"@clickbar/eslint-config-typescript": "^11.0.4",
"@types/node": "^22.4.0",
"@vue/reactivity": "^3.4.38",
"eslint": "^9.9.0",
"prettier": "^3.3.3",
"typescript": "^5.5.4",
"vite": "^5.4.1",
"vite-plugin-dts": "^4.0.3",
"vitest": "^2.0.5"
},
"scripts": {
"build": "vite build",
"test": "vitest run && vitest typecheck --run",
"lint": "eslint ./ --ext=js,ts",
"test": "vitest run --typecheck",
"lint": "eslint ./",
"prettier": "prettier . --cache",
"fix": "pnpm lint --fix && pnpm format",
"format": "pnpm prettier --write"
"fix": "pnpm lint --fix && pnpm prettier --write",
"perf": "tsc --noEmit --extendedDiagnostics --p ./performance/tsconfig.json"
}
}
# Dot Diver πŸŒŠπŸ”
A lightweight, powerful, and dependency-free TypeScript utility library that provides types and functions to work with object paths in dot notation. Dive into your objects with ease, while maintaining comprehensive type safety! πŸŽ‰
A lightweight, powerful, dependency-free and heavily over engineered TypeScript utility library providing utility types and functions to work with object paths in dot notation.
Dot 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 type correctness and productivity!
Dot 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.

@@ -112,6 +112,9 @@ Example:

> [!NOTE]
> At the moment, we can not support object properties having a '.' in their name, since this would conflict with the dot notation traversal.
<br>
<br>
### πŸ›£οΈ Path and πŸ”– PathValue
### πŸ›£οΈ Path and πŸ”– GetPathValue

@@ -121,3 +124,3 @@ <br>

```typescript
import type { Path, PathValue } from '@clickbar/dot-diver'
import type { Path, GetPathValue } from '@clickbar/dot-diver'

@@ -142,8 +145,8 @@ // Define a sample object type with nested properties

// Example 2: Using the PathValue type
type ValueAtPathA = PathValue<MyObjectType, 'a'> // Output: string
type ValueAtPathB_C = PathValue<MyObjectType, 'b.c'> // Output: number
type ValueAtPathB_D_E = PathValue<MyObjectType, 'b.d.e'> // Output: boolean
type ValueAtPathF_0 = PathValue<MyObjectType, 'f.0'> // Output: { g: string }
type ValueAtPathF_0_G = PathValue<MyObjectType, 'f.0.g'> // Output: string
// Example 2: Using the GetPathValue type
type ValueAtPathA = GetPathValue<MyObjectType, 'a'> // Output: string
type ValueAtPathB_C = GetPathValue<MyObjectType, 'b.c'> // Output: number
type ValueAtPathB_D_E = GetPathValue<MyObjectType, 'b.d.e'> // Output: boolean
type ValueAtPathF_0 = GetPathValue<MyObjectType, 'f.0'> // Output: { g: string }
type ValueAtPathF_0_G = GetPathValue<MyObjectType, 'f.0.g'> // Output: string
```

@@ -159,3 +162,3 @@

```typescript
import type { Path, PathValue } from '@clickbar/dot-diver'
import type { Path, GetPathValue } from '@clickbar/dot-diver'

@@ -170,26 +173,32 @@ // Define an object type with nested properties and a cyclic dependency

// Example 1: Using the Path type with a Depth limit
type NodePathsDepth2 = Path<Node, 2> // Depth limit of 2
// Example 1: Using the Path type with the default depth limit
type NodePathsDepth2 = Path<Node> // Depth limit of 2
// NodePathsDepth2 will be a union type representing all valid paths in dot notation up to a depth of 3:
// NodePathsDepth2 will be a union type representing all valid paths in dot notation up to a depth of 2:
// 'id' | 'label' | 'parent' | 'children' | 'parent.id' | 'parent.label' | 'parent.parent' | 'parent.children' | `parent.parent.${any}` | `parent.children.${any}` | `children.${number}` | `children.${number}.${any}`
// Example 2: Using the PathValue type with a Depth limit
type ValueAtPathParent_Id = PathValue<Node, 'parent.id', 3> // Output: number
type ValueAtPathChildren_0_Label = PathValue<Node, 'children.0.label', 3> // Output: string | undefined
type ValueAtPathParent_Parent_Parent = PathValue<Node, 'parent.parent.parent.parent', 3> // Output: unknown (due to the depth limit)
// Example 2: Using the Path type with a custom depth limit
type NodePathsDepth3 = Path<Node, never, { depth: 3; onlyWritable: false }> // Depth limit of 3
// 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:
// 'id' | 'label' | 'parent' | 'children'
// | 'parent.id' | 'parent.label' | 'parent.parent' | 'parent.children' | `parent.parent.parent'
// | `parent.parent.parent' | 'parent.parent.children' | ... etc.
```
The default depth is currently **10**.\
At the moment, it is not possible to customize it when using the provided `getByPath` and `setByPath` functions.
This is further explained in this [issue](https://github.com/clickbar/dot-diver/issues/1).
The second parameter is an `offset`. You can provide a valid path to start the autocompletion from there.\
This is used in `getByPath` and `setByPath` to provide autocompletion for the next levels, starting from the current path.
When using `getByPath` and `setByPath`, the `Depth` parameter is the lookahead depth and not the max depth.
The default depth is currently **3**.
<br>
<br>
### βš™οΈ Customizing the Depth Limit
### βš™οΈ Customizing the Depth Lookahead Limit
You can still customize it, by implementing your own functions, which just calls ours.
Example:
You can customize the set and get functions, by implementing your own variant and using the provided types.\
Here is an example where we customize the lookahead depth to 5:
<br>

@@ -200,9 +209,9 @@

import type { Path, SearchableObject, PathValue } from '@clickbar/dot-diver'
import type { Path, SearchableObject, GetPathValue, SetPathValue } from '@clickbar/dot-diver'
function getByPathDepth5<T extends SearchableObject, P extends Path<T, 5> & string>(
function getByPathDepth5<T extends SearchableObject, P extends Path<T, P, { depth: 5 }> & string>(
object: T,
path: P,
): PathValue<T, P, 5> {
return getByPath(object, path) as PathValue<T, P, 5>
): GetPathValue<T, P> {
return getByPath(object, path) as GetPathValue<T, P>
}

@@ -212,6 +221,5 @@

T extends SearchableObject,
P extends Path<T, 5> & string,
V extends PathValue<T, P, 5>,
>(object: T, path: P, value: V): void {
setByPath(object, path, value as PathValue<T, P>)
P extends Path<T, P, { onlyWriteable: true; depth: 5 }> & string,
>(object: T, path: P, value: SetPathValue<T, P>): void {
setByPath(object, path, value as SetPathValue<T, P>)
}

@@ -222,4 +230,4 @@

The intersection between `Path<T, 5>` and `string` is necessary for TypeScript to successfully narrow down the type of `P` based on the user-provided `path` input.
Without the intersection, the `path` would just be of type `Path<T, 5>` and `PathValueEntry` would be a union of all possible return types.
The intersection between `Path<T, P, { depth: 5 }>` and `string` is necessary for TypeScript to successfully narrow down the type of `P` based on the user-provided `path` input.
Without the intersection, the `path` would just be of type `Path<T, P, { depth: 5 }>` and `PathValueEntry` would be a union of all possible return types.
By using the intersection, TypeScript is forced to apply the `Path` constraints and infer the type from the provided user input.

@@ -234,4 +242,27 @@

See this [issue](https://github.com/clickbar/dot-diver/issues/2).
Paths get truncated, if they are unioned with a string. E.g. `keyof T | string`.\
This should only happen in rare cases for objects looking like this:
```typescript
type TestType = {
a: string
b: string
[key: string]: string
}
```
If your object has nested properties, for example looking like this:
```typescript
type TestType = {
a: string
b: {
c: string
}
[key: string]: string
}
```
You will get autocompletion again, as soon as you typed the path to the nested object, e.g. `b.`.
<br>

@@ -241,5 +272,5 @@

Your paths are not truncated. Typescript will still validate them.
Your paths are not truncated. TypeScript will still validate them.
Some IDEs have problems with displaying `children.${number}` paths.
If you can, define the array as an tuple. This will include all paths in the auto completion.
If you can, define the array as an tuple. This will include all paths in the autocompletion.

@@ -250,3 +281,3 @@ <br>

This 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.\
This 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.\
For example:

@@ -262,8 +293,8 @@

}
f: TestType2
f: TestType
}
```
You can try to decrease the depth limit of the auto completion by reimplementing the `getByPath` and `setByPath` functions.
See [this section](#%EF%B8%8F-customizing-the-depth-limit) for customizing the depth limit.
You can try to decrease the lookahead depth of the autocompletion by reimplementing the `getByPath` and `setByPath` functions.
See [this section](#%EF%B8%8F-customizing-the-depth-lookahead-limit).

@@ -270,0 +301,0 @@ <br>

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚑️ by Socket Inc