Created
February 8, 2025 22:48
-
-
Save okaybeydanol/ff6cce734ce50c3edfbdae4b10ca3c18 to your computer and use it in GitHub Desktop.
TypeScript: Extract Nested Object Keys as Arrays (Basic, Infer, and String-Enforced)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Recursively extracts nested keys of an object as arrays. | |
* Useful for representing nested object paths in an array format. | |
* | |
* Example: | |
* type Theme = { colors: { primary: string; secondary: { light: string; dark: string } } }; | |
* type Paths = NestedKeyArray<Theme['colors']>; | |
* ["primary"] | ["secondary", "light"] | ["secondary", "dark"] | |
*/ | |
export type NestedKeysArray<T> = T extends object | |
? { | |
[K in keyof T]: K extends string | number | |
? T[K] extends string | |
? [K] // Base case: if the value is a string, return the key as a single-element array | |
: T[K] extends object | |
? [K, ...NestedKeysArray<T[K]>] // Recursive case: if the value is an object, dive deeper | |
: never // Invalid case: neither string nor object | |
: never; // Invalid case: key is not a string or number | |
}[keyof T] | |
: never; | |
/** | |
* Recursively extracts nested keys of an object as arrays using `infer`. | |
* Useful for representing nested object paths in an array format. | |
* | |
* Example: | |
* type Theme = { colors: { primary: string; secondary: { light: string; dark: string } } }; | |
* type Paths = NestedKeysArrayInfer<Theme['colors']>; | |
* ["primary"] | ["secondary", "light"] | ["secondary", "dark"] | |
*/ | |
export type NestedKeysArrayInfer<T> = T extends object | |
? { | |
[K in keyof T]: T[K] extends infer V | |
? V extends Record<string, unknown> | |
? [K, ...NestedKeysArrayInfer<T[K]>] // Recursive case: if the value is an object, dive deeper | |
: V extends string | |
? [K] // Base case: if the value is a string, return the key | |
: never // Invalid case: neither string nor object | |
: never; // Invalid case: key is not a string or number | |
}[keyof T] | |
: never; | |
/** | |
* Recursively extracts nested keys of an object as arrays using `infer` and ensures keys are strings. | |
* Useful for representing nested object paths in an array format. | |
* | |
* Example: | |
* type Theme = { colors: { primary: string; secondary: { light: string; dark: string } } }; | |
* type Paths = NestedKeysArrayInferString<Theme['colors']>; | |
* ["primary"] | ["secondary", "light"] | ["secondary", "dark"] | |
*/ | |
export type NestedKeysArrayInferString<T> = T extends object | |
? { | |
[K in keyof T]: K extends infer N extends string | |
? T[K] extends string | |
? [N] // Base case: if the value is a string, return the key | |
: [N, ...NestedKeysArrayInferString<T[K]>] // Recursive case: if the value is an object, dive deeper | |
: T[K] extends string | |
? [K] // Base case: if the value is a string, return the key | |
: [K, ...NestedKeysArrayInferString<T[K]>]; // Recursive case: if the value is an object, dive deeper | |
}[keyof T] | |
: never; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Three utility types for recursively extracting nested object keys as arrays:
infer
.infer
for value type extraction.infer
.Examples: