索引类型

索引类型让我们可以查询和操作类型的属性类型。通过 keyof 操作符和索引访问类型,可以创建灵活且类型安全的代码。

keyof 操作符

keyof 获取类型的所有键的联合类型。

interface User {
  id: number
  name: string
  email: string
}

type UserKeys = keyof User

const key: UserKeys = "id"

UserKeys"id" | "name" | "email" 的联合类型。

索引访问类型

使用 T[K] 访问类型 T 的属性 K 的类型。

interface User {
  id: number
  name: string
  email: string
}

type UserIdType = User["id"]
type UserNameType = User["name"]

const id: UserIdType = 1
const name: UserNameType = "张三"

User["id"] 获取 id 属性的类型 number

动态属性访问

结合 keyof 和索引访问类型,可以创建动态属性访问函数。

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key]
}

const user = {
  id: 1,
  name: "张三",
  email: "zhangsan@example.com"
}

const id = getProperty(user, "id")
const name = getProperty(user, "name")

console.log(id)
console.log(name)

K extends keyof T 确保 keyT 的有效属性名,返回值类型自动推断。

数组索引类型

数组的索引类型是数字。

const arr = ["a", "b", "c"]

type ArrayType = typeof arr
type ArrayIndex = keyof ArrayType

const index: ArrayIndex = 0

数组的索引包括数字索引和数组方法名。

索引签名

索引签名定义动态属性的类型。

interface StringMap {
  [key: string]: string
}

const map: StringMap = {
  name: "张三",
  city: "北京"
}

console.log(map.name)
console.log(map.city)

[key: string]: string 表示所有字符串键的值都是字符串类型。

索引类型与泛型

索引类型与泛型结合使用,可以创建通用的工具函数。

function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
  const result = {} as Pick<T, K>
  keys.forEach(key => {
    result[key] = obj[key]
  })
  return result
}

interface User {
  id: number
  name: string
  email: string
  age: number
}

const user: User = {
  id: 1,
  name: "张三",
  email: "zhangsan@example.com",
  age: 25
}

const partial = pick(user, ["id", "name"])
console.log(partial)

pick 函数从对象中选择指定的属性,返回类型自动推断。

索引类型与映射类型

索引类型是映射类型的基础。

type Readonly<T> = {
  readonly [P in keyof T]: T[P]
}

type Partial<T> = {
  [P in keyof T]?: T[P]
}

interface User {
  id: number
  name: string
}

type ReadonlyUser = Readonly<User>
type PartialUser = Partial<User>

const readonlyUser: ReadonlyUser = {
  id: 1,
  name: "张三"
}

const partialUser: PartialUser = {
  name: "李四"
}

keyof T 获取所有键,T[P] 获取属性类型。

实际应用

索引类型在实际开发中常用于创建通用的查询函数。

interface Database {
  users: { id: number; name: string }[]
  products: { id: number; name: string; price: number }[]
  orders: { id: number; userId: number; productId: number }[]
}

function getTable<T extends keyof Database>(db: Database, table: T): Database[T] {
  return db[table]
}

const db: Database = {
  users: [{ id: 1, name: "张三" }],
  products: [{ id: 1, name: "商品", price: 100 }],
  orders: [{ id: 1, userId: 1, productId: 1 }]
}

const users = getTable(db, "users")
const products = getTable(db, "products")

console.log(users)
console.log(products)

getTable 函数根据表名返回对应的数据,类型自动推断。

小结

索引类型让我们可以查询和操作类型的属性类型。keyof 获取所有键的联合类型,T[K] 访问属性类型。索引类型与泛型结合使用,可以创建通用的工具函数。索引类型是映射类型的基础,在实际开发中常用于创建类型安全的动态属性访问。