Implement object path getter and setter
Build object path getter and setter. The interviewer expects a small, reusable utility with clear behavior under repeated calls and invalid inputs.
Answer Strategy
For object path getter and setter, start by stating the public contract before writing code: argument shape, return shape, mutation rules, error behavior, and whether work is synchronous, timed, cached, or cancellable.
A senior solution uses boring names for hidden state. If the function stores a timer, cache entry, listener, or in-flight promise, say who owns that state and how it is cleaned up.
After the baseline passes, harden the edge cases: empty input, repeated calls, invalid values, thrown callbacks, stable ordering, and memory lifetime. The reference below is written to be narrated line by line.
Reference Implementation: Object Path Get And Set
Path utilities should avoid prototype pollution and should make array/object creation rules explicit.
function assertSafeKey(key: string) {
if (key === '__proto__' || key === 'prototype' || key === 'constructor') {
throw new Error('Unsafe object path key: ' + key);
}
}
function getPath(source: unknown, path: string): unknown {
return path.split('.').reduce<unknown>((current, key) => {
if (current == null) return undefined;
return (current as Record<string, unknown>)[key];
}, source);
}
function setPath(source: Record<string, unknown>, path: string, value: unknown) {
const keys = path.split('.');
let current = source;
keys.forEach((key, index) => {
assertSafeKey(key);
if (index === keys.length - 1) {
current[key] = value;
return;
}
const next = current[key];
if (next === null || typeof next !== 'object' || Array.isArray(next)) {
current[key] = {};
}
current = current[key] as Record<string, unknown>;
});
return source;
}Runnable Playground
Edit the implementation and run the tests directly in the browser. For system design questions, the playground focuses on the core state/data logic that the UI would call.
function assertSafeKey(key: string) {
if (key === '__proto__' || key === 'prototype' || key === 'constructor') {
throw new Error('Unsafe object path key: ' + key);
}
}
function getPath(source: unknown, path: string): unknown {
return path.split('.').reduce<unknown>((current, key) => {
if (current == null) return undefined;
return (current as Record<string, unknown>)[key];
}, source);
}
function setPath(source: Record<string, unknown>, path: string, value: unknown) {
const keys = path.split('.');
let current = source;
keys.forEach((key, index) => {
assertSafeKey(key);
if (index === keys.length - 1) {
current[key] = value;
return;
}
const next = current[key];
if (next === null || typeof next !== 'object' || Array.isArray(next)) {
current[key] = {};
}
current = current[key] as Record<string, unknown>;
});
return source;
}
function setAndReturn(path: string, value: unknown) {
return setPath({}, path, value);
}Testing Strategy
Convert the answer into observable behavior. In a mid-senior interview, say which behaviors are covered by unit tests, interaction tests, accessibility checks, and one browser smoke path.
test('getPath and setPath read nested values safely', () => {
const target: Record<string, unknown> = {};
setPath(target, 'user.profile.name', 'Ada');
expect(getPath(target, 'user.profile.name')).toBe('Ada');
expect(() => setPath(target, '__proto__.polluted', true)).toThrow('Unsafe');
});Interviewer Signal
Tests whether you can turn a familiar utility into a precise contract instead of coding only the happy path.
Constraints
- Define the function signature before coding.
- Do not rely on global mutable state unless it is part of the returned closure.
- Explain time and space cost for the common path.
Model Answer Shape
- Write the smallest public contract first.
- Cover empty input, repeated calls, thrown errors, and cleanup behavior.
- Keep implementation readable enough to narrate under interview pressure.
Tradeoffs
- A compact implementation is attractive, but explicit state names are easier to debug live.
- Supporting every possible input can distract from the core contract; state the scope before coding.
Edge Cases
- No arguments or undefined callbacks.
- Synchronous throw inside the wrapped function.
- Repeated calls before the previous result settles.
Testing And Proof
- Happy path with representative inputs.
- Boundary input and repeated invocation.
- Cleanup or cancellation if timers or promises are involved.
Follow-Ups
- How would you expose cancellation?
- How would the API change for React usage?