索引访问类型
索引访问类型的基本概念
索引访问类型(Indexed Access Types)允许通过索引获取另一个类型中的属性类型。语法形式为T[K]
,其中T
是类型,K
是能够作为索引的类型(通常是字符串字面量类型或联合类型)。这种类型查询方式类似于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; }
索引访问类型与联合类型
索引访问类型可以与联合类型结合使用,获取多个属性的联合类型。当索引是联合类型时,结果类型是对应属性类型的联合。
type PersonProps = Person['name' | 'age']; // string | number
type AllValues = Person[keyof Person];
// string | number | { city: string; zipCode: string; }
嵌套属性的访问
索引访问类型支持嵌套属性的访问,可以通过链式索引来获取深层属性的类型。
type CityType = Person['address']['city']; // string
type ZipCodeType = Person['address']['zipCode']; // string
数组和元组的索引访问
索引访问类型也适用于数组和元组类型。对于数组,可以使用number
作为索引类型来获取元素类型;对于元组,可以使用数字字面量类型获取特定位置的类型。
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
与泛型结合使用
索引访问类型在泛型中特别有用,可以创建更灵活的类型操作。通过泛型参数约束,可以确保索引访问的安全性。
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
动态属性访问
索引访问类型可以用于动态计算属性类型,这在处理复杂类型系统时非常有用。
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
与映射类型结合
索引访问类型常与映射类型一起使用,可以创建基于现有类型的新类型。
type ReadonlyPerson = {
readonly [K in keyof Person]: Person[K];
};
// 等价于
type ReadonlyPerson = {
readonly name: string;
readonly age: number;
readonly address: {
city: string;
zipCode: string;
};
};
条件类型中的索引访问
在条件类型中使用索引访问类型可以实现更复杂的类型逻辑。
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 }
索引访问类型的限制
索引访问类型有一些限制需要注意:
- 索引必须是已知的属性名或联合类型
- 不能访问不存在的属性
- 对于动态计算的属性名需要额外的类型保护
// 错误示例
type Invalid1 = Person['invalid']; // 错误:类型"Person"上不存在属性"invalid"
// 需要类型保护
function safeAccess<T, K extends string>(obj: T, key: K): K extends keyof T ? T[K] : undefined {
return (obj as any)[key];
}
实际应用场景
索引访问类型在实际开发中有多种应用场景:
- 类型安全的属性访问函数
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[]
- 组件Props类型提取
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'
- API响应类型处理
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 }
高级类型操作
索引访问类型可以用于构建更高级的类型操作工具:
- 深度属性访问
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 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 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类型操作符