Flattening Object Keys with TypeScript Types
A few weeks ago, I was working on a project where I needed to get all the flattened keys from a deeply nested object as a string union. I looked around the internet, but everything I found was about flattening the keys at runtime. I was looking for the types only. I eventually figured out how to do it and wanted to document it in case others found it helpful.
Here’s the final result:
I loaded this code into the TypeScript playground if you’d like to experiment further.
This approach uses two newer TypeScript concepts: conditional types and template literals. Let’s break
FlattenObjectKeys down to see what it’s doing. First, we’re going to use generics to pass in an object’s type:
T is the type for the object we’re going to be flattening. We include
extends Record<string, unknown> to let TypeScript know this is going to be an object with unknown value types.
Key is a generic derived from all the keys of
T. With these two types, we can start checking to see what to do with each key. We’re going to use conditional types to perform these checks. You can think of conditional types as ternary statements for types. Our first check is
Key extends string. This is necessary because objects can also have
Symbols as keys, so we need to eliminate those. Here’s how that works:
This conditional type states “if
Key is a
string, continue; otherwise, ignore it and do nothing”. Now that we know that
Key is a string, we can do an additional check on the type of
Here is where we’re checking for nested objects. We’re using another conditional type to check if
T[Key] is an object. If it’s not, then we don’t need to do anything else. We return
T[Key] is an object, we use a template string to add the key to a string with a dot separator before recursively calling
T[Key] for the process to continue. With this, we can take an object with any depth of nesting and get a single string union of all the keys flattened.
Have thoughts about this blog post? Chat with me about it on Twitter!