Index access type
Basic Concepts of Indexed Access Types
Indexed Access Types allow retrieving the type of a property from another type through indexing. The syntax is T[K]
, where T
is a type and K
is a type that can serve as an index (typically a string literal type or a union type). This type query method is similar to accessing object property values via property names in JavaScript.
type Person = {
name: string;
age: number;
address: {
city: string;
zipCode: string;
};
};
type NameType = Person['name']; // string
type AgeType = Person['age']; // number
type AddressType = Person['address']; // { city: string; zipCode: string; }
Indexed Access Types and Union Types
Indexed Access Types can be combined with union types to retrieve a union of multiple property types. When the index is a union type, the resulting type is a union of the corresponding property types.
type PersonProps = Person['name' | 'age']; // string | number
type AllValues = Person[keyof Person];
// string | number | { city: string; zipCode: string; }
Accessing Nested Properties
Indexed Access Types support accessing nested properties through chained indices to retrieve the types of deeply nested properties.
type CityType = Person['address']['city']; // string
type ZipCodeType = Person['address']['zipCode']; // string
Indexed Access for Arrays and Tuples
Indexed Access Types also apply to array and tuple types. For arrays, you can use number
as the index type to retrieve the element type; for tuples, you can use numeric literal types to retrieve the type at a specific position.
type StringArray = string[];
type ElementType = StringArray[number]; // string
type Tuple = [string, number, boolean];
type First = Tuple[0]; // string
type Second = Tuple[1]; // number
type All = Tuple[number]; // string | number | boolean
Combining with Generics
Indexed Access Types are particularly useful in generics, enabling more flexible type operations. By constraining generic parameters, you can ensure the safety of indexed access.
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const person: Person = {
name: 'Alice',
age: 30,
address: {
city: 'New York',
zipCode: '10001'
}
};
const name = getProperty(person, 'name'); // string
const age = getProperty(person, 'age'); // number
Dynamic Property Access
Indexed Access Types can be used to dynamically compute property types, which is highly useful when working with complex type systems.
type DynamicAccess<T, K extends string> = K extends keyof T ? T[K] : never;
type Result1 = DynamicAccess<Person, 'name'>; // string
type Result2 = DynamicAccess<Person, 'email'>; // never
Combining with Mapped Types
Indexed Access Types are often used with mapped types to create new types based on existing ones.
type ReadonlyPerson = {
readonly [K in keyof Person]: Person[K];
};
// Equivalent to
type ReadonlyPerson = {
readonly name: string;
readonly age: number;
readonly address: {
city: string;
zipCode: string;
};
};
Indexed Access in Conditional Types
Using Indexed Access Types in conditional types enables more complex type logic.
type NonFunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? never : K
}[keyof T];
type NonFunctionProperties<T> = Pick<T, NonFunctionPropertyNames<T>>;
interface MixedInterface {
id: number;
name: string;
log: () => void;
update: (data: any) => void;
}
type DataProps = NonFunctionProperties<MixedInterface>;
// { id: number; name: string }
Limitations of Indexed Access Types
Indexed Access Types have some limitations to note:
- The index must be a known property name or union type.
- You cannot access non-existent properties.
- Additional type guards are needed for dynamically computed property names.
// Error example
type Invalid1 = Person['invalid']; // Error: Property 'invalid' does not exist on type 'Person'
// Requires type guarding
function safeAccess<T, K extends string>(obj: T, key: K): K extends keyof T ? T[K] : undefined {
return (obj as any)[key];
}
Practical Use Cases
Indexed Access Types have various practical applications in real-world development:
- Type-safe property access functions
function pluck<T, K extends keyof T>(items: T[], key: K): T[K][] {
return items.map(item => item[key]);
}
const people: Person[] = [
{ name: 'Alice', age: 30, address: { city: 'NY', zipCode: '10001' } },
{ name: 'Bob', age: 25, address: { city: 'LA', zipCode: '90001' } }
];
const names = pluck(people, 'name'); // string[]
const ages = pluck(people, 'age'); // number[]
- Extracting component Props types
interface ButtonProps {
size: 'small' | 'medium' | 'large';
variant: 'primary' | 'secondary';
onClick: () => void;
disabled?: boolean;
}
type ButtonSize = ButtonProps['size']; // 'small' | 'medium' | 'large'
type ButtonVariant = ButtonProps['variant']; // 'primary' | 'secondary'
- Handling API response types
interface ApiResponse<T> {
data: T;
status: number;
error?: string;
}
type ExtractData<T> = T extends ApiResponse<infer U> ? U : never;
type UserResponse = ApiResponse<{ id: string; name: string }>;
type UserData = UserResponse['data']; // { id: string; name: string }
Advanced Type Operations
Indexed Access Types can be used to build more advanced type manipulation tools:
- Deep property access
type DeepAccess<T, K extends string> =
K extends keyof T ? T[K] :
K extends `${infer First}.${infer Rest}` ?
First extends keyof T ? DeepAccess<T[First], Rest> :
never :
never;
type PersonCity = DeepAccess<Person, 'address.city'>; // string
- Type-safe path access
type PathImpl<T, K extends keyof T> =
K extends string ?
T[K] extends Record<string, any> ?
`${K}.${PathImpl<T[K], keyof T[K]>}` | K :
K :
never;
type Path<T> = PathImpl<T, keyof T>;
type PersonPath = Path<Person>;
// "name" | "age" | "address" | "address.city" | "address.zipCode"
- Type retrieval based on paths
type PathValue<T, P extends Path<T>> =
P extends `${infer K}.${infer Rest}` ?
K extends keyof T ? PathValue<T[K], Rest & Path<T[K]>> : never :
P extends keyof T ? T[P] : never;
type ZipCodeType = PathValue<Person, 'address.zipCode'>; // string
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:typeof类型操作符