Skip to content

索引访问类型 (Indexed Access Types)

索引访问类型是 TypeScript 中一种强大的功能,它允许你根据键名从类型中提取出相应的属性类型。这在需要动态地操作对象的属性或处理复杂类型时非常有用。通过使用索引访问类型,你可以更精确地控制和推断代码中的类型信息。

基本概念

索引访问类型的基本语法如下:

typescript
type PropertyType = ObjectType[KeyType];

其中,ObjectType 是你要从中提取属性类型的对象类型,而 KeyType 是你用来指定要提取哪个属性的键类型。

示例

假设我们有一个接口 Person

typescript
interface Person {
  name: string;
  age: number;
}

我们可以使用索引访问类型来提取特定属性的类型:

typescript
type NameType = Person["name"]; // string
type AgeType = Person["age"]; // number

在这个例子中,Person["name"] 提取了 name 属性的类型 string,而 Person["age"] 提取了 age 属性的类型 number

使用泛型与 keyof

索引访问类型经常与泛型和 keyof 操作符结合使用,以创建更加灵活和通用的类型工具。例如:

typescript
type GetPropType<T, K extends keyof T> = T[K];

interface Person {
  name: string;
  age: number;
}

type PersonName = GetPropType<Person, "name">; // string
type PersonAge = GetPropType<Person, "age">; // number

在这个例子中,GetPropType<T, K> 是一个工具类型,它接受一个对象类型 T 和一个键 K,并返回该键对应的属性类型。K extends keyof T 确保了 K 必须是 T 的有效键。

处理联合类型

当索引访问类型的键是一个联合类型时,结果将是所有可能属性类型的联合:

typescript
interface Person {
  name: string;
  age: number;
}

type NameOrAge = Person["name" | "age"]; // string | number

在这个例子中,Person['name' | 'age'] 返回的是 string | number,因为 nameage 分别是 stringnumber 类型。

结合条件类型

索引访问类型可以与条件类型结合使用,以实现更复杂的类型逻辑。例如,我们可以创建一个工具类型来提取对象中所有函数属性的类型:

typescript
type FunctionPropertyNames<T> = {
  [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;
}[keyof T];

type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>;

interface Part {
  id: number;
  getName(): string;
}

type FuncProps = FunctionProperties<Part>; // { getName: () => string }

在这个例子中,FunctionProperties<T> 使用索引访问类型和条件类型来提取 T 中所有的函数属性,并返回一个新的类型,该类型只包含这些函数属性。

使用模板字面量类型

模板字面量类型可以与索引访问类型结合使用,以实现更复杂的键模式匹配。例如:

typescript
type EventConfig = {
  onMouseEnter: string;
  onMouseLeave: string;
};

type ExtractEventPrefix<T> = T extends `on${infer U}` ? U : never;

type EventPrefixes = ExtractEventPrefix<keyof EventConfig>; // "MouseEnter" | "MouseLeave"

在这个例子中,ExtractEventPrefix 使用模板字面量类型来匹配并提取事件前缀。

实际应用案例

假设我们有一个配置对象,希望创建一个函数来安全地更新其属性:

typescript
interface Config {
  host: string;
  port: number;
  debug: boolean;
}

function updateConfig<K extends keyof Config>(
  config: Config,
  key: K,
  value: Config[K]
): void {
  config[key] = value;
}

const config: Config = {
  host: "localhost",
  port: 8080,
  debug: true,
};

updateConfig(config, "host", "127.0.0.1"); // OK
updateConfig(config, "port", 9000); // OK
updateConfig(config, "debug", false); // OK
// updateConfig(config, "unknown", "value"); // Error, "unknown" is not a valid key of Config

在这个例子中:

  • keyof Config 提取了 Config 接口的所有键。
  • K extends keyof Config 确保了 key 参数只能是 Config 接口中的有效键。
  • Config[K] 使用索引访问类型确保 value 参数的类型与 key 对应的属性类型匹配。

总结

索引访问类型是 TypeScript 中一个强大且灵活的功能,它允许你根据键名从类型中提取出相应的属性类型。通过合理使用索引访问类型,你可以构建更加健壮和灵活的类型系统,提高代码的安全性和可维护性。

Released under the MIT License.