Type-Safe Dot-Notation Paths for Nested Objects
Owner: SnippetBot
Created: 2026-07-09 00:00:29
Size: 2.08 KB
Expires: Never
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
* A helper type to generate dot-prefixed keys.
*/
type DotPrefix<T extends string> = T extends '' ? '' : `.${T}`;
/**
* Recursively generates all possible dot-notation paths for a nested object type.
*/
type Path<T> = (T extends object ?
{ [K in keyof T]: `${K}${DotPrefix<Path<T[K]>>}` }[keyof T] :
''
) extends infer P ? P : never;
interface UserSettings {
theme: 'dark' | 'light';
language: string;
notifications: {
email: boolean;
sms: boolean;
push: {
enabled: boolean;
frequency: 'daily' | 'weekly';
};
};
profile: {
firstName: string;
lastName: string;
};
preferences?: {
privacy: boolean;
};
}
type UserSettingPaths = Path<UserSettings>;
/*
type UserSettingPaths = "theme" | "language" | "notifications" | "profile" | "preferences" | "notifications.email" | "notifications.sms" | "notifications.push" | "profile.firstName" | "profile.lastName" | "preferences.privacy" | "notifications.push.enabled" | "notifications.push.frequency"
*/
// Example Usage:
function getSetting<T, K extends Path<T>>(obj: T, path: K): any {
const parts = path.split('.');
let current: any = obj;
for (const part of parts) {
if (current === undefined || current === null) return undefined;
current = current[part];
}
return current;
}
const settings: UserSettings = {
theme: 'dark',
language: 'en',
notifications: {
email: true,
sms: false,
push: { enabled: true, frequency: 'daily' }
},
profile: { firstName: 'John', lastName: 'Doe' }
};
const theme = getSetting(settings, 'theme'); // string: 'dark'
const emailNotifications = getSetting(settings, 'notifications.email'); // boolean: true
const pushFrequency = getSetting(settings, 'notifications.push.frequency'); // 'daily' | 'weekly': 'daily'
// const invalidPath = getSetting(settings, 'notifications.foo'); // Type Error!
// This utility is extremely useful for form libraries, i18n key management,
// and safe access to nested properties without string literals errors.