You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于键名缩小对象属性类型?TypeScript类型收窄问题

TypeScript对象遍历函数的类型缩小问题

原始遍历函数

function iterate<O extends Record<string, unknown>>(o: O, cb: (key: keyof O, value: O[keyof O], obj: O) => void) {
  for (const key in o) {
    if (o.hasOwnProperty(key)) {
      cb(key, o[key], o);
    }
  }
}

问题场景

使用上述函数遍历具体对象时,回调内通过键名判断无法缩小value的类型,但通过对象索引却能实现类型缩小:

iterate({
  name: "Sally",
  age: 30,
}, (key, value, obj) => { // key: "name" | "age"; value: string | number
  if (key === "name") {
    const indexedValue = obj[key]; // indexedValue: string;
    console.log(value.toUpperCase(), indexedValue.toUpperCase()); // value.toUpperCase() 类型报错
  } else {
    const indexedValue = obj[key]; // indexedValue: number;
    console.log(value.toFixed(), indexedValue.toFixed()); // value.toFixed() 类型报错
  }
});

解决方案:修改泛型实现类型关联

可以通过调整iterate函数的泛型定义,让回调的key和value建立一一对应的类型关联,从而实现键名判断后的类型缩小:

function iterate<O extends Record<string, unknown>>(
  o: O,
  cb: <K extends keyof O>(key: K, value: O[K], obj: O) => void
) {
  for (const key in o) {
    if (o.hasOwnProperty(key)) {
      cb(key as keyof O, o[key], o);
    }
  }
}

修改后,当在回调内判断key === "name"时,TypeScript会自动将value的类型缩小为string;else分支中value会被缩小为number,相关方法调用不再报错。

原问题的原因解析

  1. 原函数的类型缺陷:
    原函数的回调参数中,key是keyof O联合类型,value是O[keyof O]联合类型,但两者之间没有绑定关联关系——TypeScript仅知道key是对象的某个键、value是对象的某个属性值,无法确定当前key和value属于同一个属性。

  2. 索引操作的类型缩小逻辑:
    当通过obj[key]取值时,TypeScript会利用索引访问的类型特性:一旦key被判断为具体的字面量类型(如"name"),它会直接关联到obj对应属性的类型,因为obj的类型是明确的O,索引操作和当前key的具体值直接绑定,因此能正确缩小类型。


内容的提问来源于stack exchange,提问作者Jimmy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 21:50:22