🧠 TypeScript — Indexed Access Types: Complete Guide with Examples
🧲 Introduction – Why Use Indexed Access Types?
In TypeScript, Indexed Access Types allow you to reference the type of a specific property from another type. This powerful mechanism promotes type reusability, accuracy, and type safety—especially useful when working with complex objects, generics, or deeply nested types.
🎯 What You’ll Learn:
- What indexed access types are
- How to use them with keys, unions, arrays, and generics
- Detailed explanations for every code snippet
- Real-world usage patterns
📘 What Are Indexed Access Types?
Indexed Access Types let you dynamically reference a type of a property using its key:
type PropertyType = TypeName[Key];
TypeName: any object type (e.g., interface, type alias)Key: the name of a property in the object type
🧪 Example 1: Extracting a Property Type
type User = {
name: string;
age: number;
};
type NameType = User["name"]; // string
type AgeType = User["age"]; // number
🔍 Explanation:
Useris a type with two properties:name(string) andage(number).User["name"]accesses the type of thenameproperty — which isstring.User["age"]accesses the type of theageproperty — which isnumber.
You don’t need to repeat the structure manually. This ensures automatic consistency with the User type.
🔁 Example 2: Using keyof with Indexed Access Types
type UserKeys = keyof User; // "name" | "age"
type ValueTypes = User[UserKeys]; // string | number
🔍 Explanation:
keyof Userreturns a union of all keys:"name" | "age".User[UserKeys]means we’re accessing bothUser["name"]andUser["age"]— resulting in a union of their types:string | number.
This is how you extract all value types from an object type dynamically.
🔗 Example 3: Indexing with Union of Keys
type Person = {
id: number;
name: string;
active: boolean;
};
type IdOrStatus = Person["id" | "active"]; // number | boolean
🔍 Explanation:
- You’re accessing two properties at once:
id(number) andactive(boolean). - The result is a union:
number | boolean.
✅ This pattern is useful when extracting specific subsets of property types.
🔄 Example 4: Indexed Access with Arrays
type Roles = ["admin", "user", "guest"];
type Role = Roles[number]; // "admin" | "user" | "guest"
🔍 Explanation:
Rolesis a tuple (fixed-length array) with three string literals.- Using
Roles[number]means we’re asking: “What is the type of any element inRoles?” - Since it’s a union of all possible index values (
0,1,2), the result is"admin" | "user" | "guest".
📌 This is commonly used for defining value enums or dropdown options.
🧰 Example 5: Type-Safe Property Accessor Function
function getValue<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const product = { id: 101, name: "Notebook", price: 500 };
const id = getValue(product, "id"); // number
const name = getValue(product, "name"); // string
🔍 Explanation:
Tis a generic type representing any object.K extends keyof Tensures thatkeymust be a valid property ofT.T[K]dynamically returns the type of that property.
This prevents typos and incorrect property access during development.
🔍 Example 6: Nested Indexed Access Types
type Profile = {
user: {
name: string;
contact: {
email: string;
phone: string;
};
};
};
type ContactType = Profile["user"]["contact"]; // { email: string; phone: string }
type EmailType = Profile["user"]["contact"]["email"]; // string
🔍 Explanation:
- You’re chaining property access to go deep inside nested objects.
Profile["user"]gives you the type of theuserobject.- Adding another layer:
["contact"], and then["email"]gives the final string type.
✅ This is particularly useful when working with API response types or configuration schemas.
🧪 Example 7: With Mapped Types & keyof
type Car = {
brand: string;
year: number;
};
type CarProperties = {
[K in keyof Car]: Car[K];
};
🔍 Explanation:
- This is a mapped type.
- For each key in
Car, we get its type viaCar[K]using indexed access. - The result is effectively the same as the original
Cartype.
📌 This pattern is how many built-in utility types (like Pick, Record, Partial) work.
✅ Best Practices for Indexed Access Types
- 💡 Use with generics: Great for reusable functions.
- 🔁 Avoid repetition: DRY your types by referencing them instead of rewriting.
- 🛡️ Type safety: Reduces runtime errors from invalid property access.
📌 Summary – Recap & Use Cases
Indexed access types are a foundational feature of TypeScript that allows developers to look up property types dynamically. Whether you’re working with generics, APIs, or arrays, this approach ensures better scalability and type integrity.
🔍 Key Takeaways:
- Use
Type["key"]to extract the type of a property - Combine with
keyofto iterate through keys - Supports deep indexing and union keys
- Widely used in utility types, schema validation, and component props
⚙️ Real-World Scenarios:
- Extracting data from deeply nested API responses
- Validating form fields based on object structure
- Creating reusable, safe dynamic functions
❓ FAQs
❓ What is the difference between typeof and indexed access types?
| Feature | typeof | Indexed Access Type |
|---|---|---|
| Purpose | Extracts type from a value | Extracts type from a property |
| Usage | typeof someValue | SomeType["property"] |
| Example | typeof user | User["name"] |
❓ Can indexed access types work with tuples and arrays?
✅ Yes! Use numeric keys:
type MyTuple = [string, number];
type First = MyTuple[0]; // string
type Second = MyTuple[1]; // number
❓ Do utility types in TypeScript use indexed access?
✅ Absolutely! Built-in types like Pick<T, K> and Record<K, T> heavily rely on this feature under the hood.
❓ Is it safe to use nested indexed types?
✅ Yes, and it’s encouraged for API-heavy or config-heavy applications. Just ensure the path exists, or combine with optional chaining types (?. for runtime, Partial for types).
Share Now :
