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 :
