🧠 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:
User
is a type with two properties:name
(string) andage
(number).User["name"]
accesses the type of thename
property — which isstring
.User["age"]
accesses the type of theage
property — 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 User
returns 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:
Roles
is 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:
T
is a generic type representing any object.K extends keyof T
ensures thatkey
must 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 theuser
object.- 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
Car
type.
📌 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
keyof
to 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 :