You need to enable JavaScript to run this app. TypeScript 实现嵌套属性数组按首元素属性推导对应reader函数的类型校验
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript 实现嵌套属性数组按首元素属性推导对应reader函数的类型校验

问题根因
  • 原有类型定义的核心缺陷是泛型分发后的联合数组丢失了属性与reader函数的绑定关系:当K extends keyof T是keyof T联合类型时,泛型分发生成的元组类型为["name", reader<string>] | ["age", reader<number>] | ["sex", reader<HeroSex>],对应的数组类型是这个联合类型的数组。TS在做类型检查时,会基于数组协变、函数参数逆变的规则允许跨分支兼容:比如["sex", readNumber]可以兼容["sex", reader<HeroSex>]分支(因为数字枚举HeroSex本质是number的子类型,reader<number>根据逆变规则是reader<HeroSex>的合法子类型),最终导致类型校验失效。
  • 原有写法没有捕捉传入数组的具体元组结构,TS无法对每个数组元素做单独的键与reader的绑定校验,只能在宽松的联合数组范围内做兼容判断。
修复方案
  • 调整类型定义,实现逐元素的精确校验,强制每个数组元素的属性名、对应属性值类型与reader函数严格匹配
  • 保持原有的函数签名逻辑与调用形式不变,仅优化类型层的校验规则

修复后的完整代码:

enum HeroSex {
  male,
  female,
  unknown,
}

interface Hero {
  name: string;
  age: number;
  sex: HeroSex;
}

type reader<T> = (value: T) => void;

// 新增:精确类型相等检查工具,避免函数逆变导致的宽松兼容
type ExactEqual<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false;

// 调整readProperties的泛型签名,自动捕捉传入的reader数组结构并逐元素校验
const readProperties = <
  T extends object,
  R extends Array<[keyof T, (value: any) => void]>
>(
  Obj: T,
  readers: R extends Array<infer Elem>
    ? Elem extends [infer PropKey, infer ReaderFn]
      ? PropKey extends keyof T
        ? ExactEqual<ReaderFn, reader<T[PropKey]>> extends true
          ? Elem
          : [PropKey, reader<T[PropKey]>]
        : never
      : never
    : never[]
) => {
  for (const [prop, reader] of readers) {
    reader(Obj[prop as keyof T]);
  }
};

const readString: reader<string> = (value) => {
  console.log(`the string is ${value}`);
};

const readNumber: reader<number> = (value) => {
  console.log(`the number is ${value.toFixed()}`);
};

const readHeroSex: reader<HeroSex> = (value) => {
  console.log(`the enum is ${value.toString()}`);
};

const realHero: Hero = {
  name: "batman",
  age: 38,
  sex: HeroSex.male,
};
校验效果
  • 属性名支持自动补全:输入数组第一个元素时,TS会提示name/age/sex三个合法选项
  • 严格的类型匹配:传入["sex", readNumber]时,TS会抛出类型错误,提示该位置需要reader<HeroSex>类型的函数,不接受仅接收number的reader
  • 合法调用无报错:传入["sex", readHeroSex]、["age", readNumber]、["name", readString]的组合时,可正常通过类型校验
  • 原有API调用逻辑完全不变,无需修改业务代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.05 22:27:08