Skip to content

Instantly share code, notes, and snippets.

@KonstantinBozhkov
Last active December 30, 2021 16:12
Show Gist options
  • Save KonstantinBozhkov/df7bfb6e50d9ef0d6b60e4250bd9f1e6 to your computer and use it in GitHub Desktop.
Save KonstantinBozhkov/df7bfb6e50d9ef0d6b60e4250bd9f1e6 to your computer and use it in GitHub Desktop.
How to get literal paths of an object TypeScript
// Vertexes = "user" | "user.address" | "user.address.state" | "user.address.city" | "user.phone"
type Vertexes = VertexesOfTree<{
user: {
address: {
state: string,
city: string
},
phone: number
} }>
export type VertexesOfTree<T extends {}, P extends string = ``> = T extends {
[K in infer A]: any
}
? A extends string
? T[A] extends object
? `${P}${A}` | VertexesOfTree<T[A], `${P}${A}.`>
: `${P}${A}`
: never
: never;
/* Vertexes =
`users` |
`users[${number}].address` |
`users[${number}].address.state` |
`users[${number}].address.city` |
`users[${number}].address.postcode` |
`users[${number}].address.postcode.zip` |
`users[${number}].phone` |
`users[${number}].friends` |
`users[${number}].friends[${number}].name`*/
type Vertexes = VertexesOfTree<{
users: {
address: {
state: string;
city: string;
postcode: {
zip: number
}
};
phone: number;
friends: {
name: string
}[]
}[];
}>;
export type VertexesOfTree<T, P extends string = ``> = T extends any[]
? VertexesOfTree<T[number], `${P}[${number}].`>
: T extends object
? T extends { [K in infer A]: any }
? A extends string
? T[A] extends object
? `${P}${A}` | VertexesOfTree<T[A], T[A] extends any[] ? `${P}${A}` : `${P}${A}.`>
: `${P}${A}`
: never
: never
: never;
// TerminalVertexes = "user.address.state" | "user.address.city" | "user.phone"
type TerminalVertexes = TerminalVertexesOfTree<{
user: {
address: {
state: string,
city: string
},
phone: number
} }>
export type TerminalVertexesOfTree<T extends {}, P extends string = ``> = T extends {
[K in infer A]: any
}
? A extends string
? T[A] extends object
? TerminalVertexesOfTree<T[A], `${P}${A}.`>
: `${P}${A}`
: never
: never;
/* TerminalVertexes =
`users[${number}].address.state` |
`users[${number}].address.city` |
`users[${number}].address.postcode.zip` |
`users[${number}].phone` |
`users[${number}].friends[${number}].name`*/
type TerminalVertexes = TerminalVertexesOfTree<{
users: {
address: {
state: string;
city: string;
postcode: {
zip: number
}
};
phone: number;
friends: {
name: string
}[]
}[];
export type TerminalVertexesOfTree<T, P extends string = ``> = T extends any[]
? TerminalVertexesOfTree<T[number], `${P}[${number}].`>
: T extends object
? T extends { [K in infer A]: any }
? A extends string
? T[A] extends object
? TerminalVertexesOfTree<T[A], T[A] extends any[] ? `${P}${A}` : `${P}${A}.`>
: `${P}${A}`
: never
: never
: never;
@KonstantinBozhkov
Copy link
Author

KonstantinBozhkov commented Dec 30, 2021

You can learn more about template literal here: https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment