Reading Data Safely
Relevant source files
The following files were used as context for generating this wiki page:
Reading data safely within the data-path library refers to the ability to extract values from deeply nested object structures without the risk of runtime exceptions such as "Cannot read properties of undefined." This is achieved through the .get() method and the .fn accessor shorthand, which implement defensive traversal logic to handle missing intermediate properties.
The library ensures that if any segment of a defined path is missing in the target data object, the operation gracefully returns undefined rather than throwing an error. This behavior is consistent across standard paths and Template Paths, where wildcards are used to match multiple data points.
Core Data Extraction Logic
The primary mechanism for safe data retrieval is implemented in the PathImpl class. When the .get(data) method is invoked, the library iterates through the pre-captured path segments and traverses the provided data object step-by-step.
The Traversal Process
The traversal logic uses a fail-fast approach for null or undefined intermediate values. If at any point the current value being inspected is null or undefined, the loop terminates and returns undefined.
This diagram illustrates the iterative check performed during path traversal to prevent runtime errors.
Sources: src/impl/path-impl.ts:62-71, README.md:43-50
Key Methods and Components
| Component | Type | Description |
|---|---|---|
get(data: T) | Method | Safely extracts the value at the path. Returns undefined if any intermediate property is missing. |
fn | Getter | Returns an accessor function (data: T) => V suitable for use in .map() or .filter(). |
segments | Property | A readonly array of string or number representing the keys to traverse. |
Sources: src/types.ts:139-155, src/impl/path-impl.ts:62-78
Accessor Functions for Functional Programming
The fn property provides a convenient shorthand for extracting data within functional programming patterns. It wraps the .get() logic into a reusable function, which is particularly useful for transforming arrays of objects.
const namePath = path<User>(p => p.profile.firstName);
const users = [{ profile: { firstName: "Alice" } }, { profile: undefined }];
// Safely extracts ["Alice", undefined]
const names = users.map(namePath.fn);
Sources: src/impl/path-impl.ts:76-78, README.md:120-125
Template-Based Bulk Reading
When working with TemplatePath (paths containing * or ** wildcards), safe reading is extended to multiple matches. The library resolves the template into concrete paths based on the actual structure of the data provided.
Multi-Value Retrieval Flow
The TemplatePathImpl overrides the standard get behavior to return an array of all matched values. It first "expands" the template against the data to find all existing concrete paths and then performs a safe read on each.
This sequence shows how a template path coordinates multiple safe read operations to return a collection of values.
Sources: src/impl/template-path-impl.ts:114-116, src/types.ts:245-251
Wildcard Behavior
- Single Wildcard (
*): Matches all keys at a specific level (e.g., all indices in an array). - Deep Wildcard (
**): Recursively matches properties at any depth.
If a template is expanded against data where the target collection is missing or empty, it returns an empty array [] rather than failing.
Sources: src/impl/template-path-impl.ts:74-106, src/tests/templates.spec.ts:88-93
Safety Constraints and Edge Cases
The library's safe reading implementation accounts for several JavaScript-specific edge cases:
- Null/Undefined Roots: If the root data passed to
.get()isnullorundefined, the method immediately returnsundefinedwithout attempting to access properties. - Primitive Traversal: If a path segment attempts to traverse into a primitive value (e.g., trying to access
a.b.cwherea.bis a string), the system identifies that the property does not exist on the object and returnsundefined. - Numeric Keys: The system distinguishes between "canonical array indices" (like
"0","1") and numeric-looking object keys (like"01"or"1e3"). Safe reading preserves these distinctions to ensure the correct key is accessed.
Sources: src/tests/data-access.spec.ts:31-35, src/utils.ts:10-15, src/impl/path-impl.ts:64-66
Conclusion
Reading data safely is a core pillar of the data-path library, providing a type-safe and runtime-resilient alternative to manual null-checking. By encapsulating traversal logic within the PathImpl and TemplatePathImpl classes, the library allows developers to focus on data manipulation and UI binding without the overhead of defensive programming against deep object structures.