Introduction: Why Do You Need Interface Keys as an Array?
Imagine: you are working on a large TypeScript project, and you need to iterate over all fields of a complex object, generate a dynamic form in React, filter data, or simply list the available properties. The problem is that TypeScript is a superset of JavaScript, and its types only exist at compile time. At runtime, they disappear. So what to do? How can you get TypeScript interface keys as an array of strings to use them in real code?
A question that haunts thousands of developers on Stack Overflow. Today, in 2025, we will break down all possible approaches: from simple and reliable to advanced. You will learn how to make TypeScript work for you, not against you. Let's go!
The Problem: "Disappearing" Types
Let's look at the root of the problem right away. Suppose you have an interface like this:
interface User { id: number; name: string; email: string; isAdmin: boolean;}You need to get an array of strings: ['id', 'name', 'email', 'isAdmin']. The first thing that comes to mind is using Object.keys(). But there is a nuance. If you try to write this:
const keys = Object.keys({} as User);// Type: string[]TypeScript will return the type string[], not ('id' | 'name' | 'email' | 'isAdmin')[]. This is useless — you lose all information about the specific keys.
Why does this happen? Because Object.keys() in JavaScript always returns an array of strings. TypeScript cannot know for sure which keys an object will have at runtime (for example, if the object is extended). Therefore, it gives the safest, but useless, type.
Solution 1: "Manual" Array (Simplicity and Safety)
The simplest and recommended for 90% of cases way is to create an array manually and infer the type from it. This is not a joke. This approach guarantees that your array will always be synchronized with the interface.
// 1. Define the array of keysexport const USER_KEYS = ['id', 'name', 'email', 'isAdmin'] as const;
// 2. Infer the type from the arraytype UserKey = typeof USER_KEYS[number]; // 'id' | 'name' | 'email' | 'isAdmin'
// 3. Use it for the interfaceinterface User { [key in UserKey]: key extends 'id' ? number : key extends 'name' ? string : key extends 'email' ? string : boolean;}
// 4. Get the array of stringsconst keys: string[] = [...USER_KEYS];console.log(keys); // ['id', 'name', 'email', 'isAdmin']Pros: Full typing, no magic tricks, easy to read and maintain.
Cons: You need to maintain two places (the interface and the array) manually.
Solution 2: Utility Type with keyof (Advanced, but with Caveats)
TypeScript provides the keyof operator, which returns a union of keys. But how do you turn this union into an array of strings? In 2025, this still requires a small trick.
The classic way is to use a helper function that checks types at compile time:
// Helper functionfunction getKeys<T>(obj: T): (keyof T)[] { return Object.keys(obj) as (keyof T)[];}
// Usageinterface Product { title: string; price: number; inStock: boolean;}
const product: Product = { title: 'Keyboard', price: 100, inStock: true};
const productKeys = getKeys(product);// Type: ("title" | "price" | "inStock")[]console.log(productKeys); // ['title', 'price', 'inStock']Important: This method only works if you have a real object that matches the interface. If you only have an interface but no object, you will need to create