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

如何用TypeScript第一个参数约束后两个参数的计算属性名类型?

实现基于属性名约束的可复用includes函数

我想要做一个可复用的includes函数,要求第一个参数传属性名,后面的列表和值参数必须包含这个属性。最开始的代码是这样的:

type Primitive = string | boolean | number;

export const includesByAttribute = (
  attr: string,
  list: { [attr]: Primitive }[],
  val: { [attr]: Primitive },
) => {
  if (list.length > 0) return list.find((obj) => obj[attr] === val[attr]);
  return false;
};

后来改了写法,但还是没实现约束效果:

export const includesByAttribute = (
  attr: string,
  list: { [attr: string]: Primitive }[],
  val: { [attr: string]: Primitive },
) => {
  if (list.length > 0) return list.find((obj) => obj[attr] === val[attr]);
  return false;
};

比如调用时传了不匹配的属性名,代码居然还能正常编译,完全不符合预期:

includesByAttribute('value', [{ x: 1 }], { x: 2 }) // 可编译但不符合预期

要让第一个参数的属性名能约束后两个参数的类型,得用TypeScript的泛型来捕获属性名字面量类型,这样列表和值的类型就能跟着这个属性名走。

基础实现版本

type Primitive = string | boolean | number;

export const includesByAttribute = <K extends string>(
  attr: K,
  list: Record<K, Primitive>[],
  val: Record<K, Primitive>,
) => {
  return list.length > 0 ? list.find(obj => obj[attr] === val[attr]) : false;
};

这么写之后:

  • 泛型K会抓牢你传入的具体属性名(比如'value')
  • Record<K, Primitive>强制要求列表里的每个对象和值对象都必须有K这个属性,而且属性值得是Primitive类型
  • 再调用includesByAttribute('value', [{ x: 1 }], { x: 2 })就会直接报编译错误,完全符合预期

更灵活的版本(允许对象带额外属性)

如果需要列表里的对象可以有其他多余属性,只约束指定属性的存在性,可以改成这样:

type Primitive = string | boolean | number;

export const includesByAttribute = <K extends string, T extends Record<K, Primitive>>(
  attr: K,
  list: T[],
  val: Pick<T, K>,
) => {
  return list.length > 0 ? list.find(obj => obj[attr] === val[attr]) : false;
};

这个版本的好处是:

  • 泛型T表示列表里对象的具体类型,只要它包含K属性就行,其他属性随便加
  • Pick<T, K>允许值对象只带T类型里的K属性,不用完全跟列表对象的结构一致

内容的提问来源于stack exchange,提问作者Marc Sloth Eastman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 04:34:59