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

如何让TypeScript函数的idKey与idValue参数类型关联?

编译阶段确保idKey与idValue类型一致的TypeScript解决方案

原函数代码

/**
 * 检查字符串类型的值是否已存在于数据数组中
 * @param data 数据数组
 * @param key 要检查的字符串属性键
 * @param value 要检查的字符串值
 * @param idKey 用于排除自身条目的id属性键(可选)
 * @param idValue 对应idKey的属性值(可选)
 * @returns 如果值存在于数组中则返回true
 */
function checkIfStringIsDuplicated<K extends PropertyKey, H extends PropertyKey = never>(
  data: Array<Partial<Record<K, string | null>> & Partial<Record<NoInfer<H>, string | number | null>>>,
  key: K,
  value: string,
  idKey?: H,
  idValue?: string | number | null
): boolean {
  return !!data.find((item) => {
    // 如果在数据数组中找到匹配的值
    if (item[key] && item[key]?.trim().toLowerCase() === value.trim().toLowerCase()) {
      // 检查该条目的id是否与传入的idValue匹配
      // 如果匹配,说明是当前正在编辑的条目,不算重复
      // 如果不匹配,则判定为重复
      if (idKey && item[idKey] && idValue) {
        if (typeof item[idKey] !== typeof idValue)
          throw new Error(
            `DuplicateValidationService: ${item[idKey]}的类型(${typeof item[idKey]})与${idValue}的类型(${typeof idValue})不匹配`
          );
        return !(item[idKey] === idValue);
      } else {
        // 如果未提供idKey或条目无ID,则判定为重复
        return true;
      }
    } else {
      return false;
    }
  });
}

基础用法示例

interface Car {
  id: number;
  name: string;
}

const dataArray: Array<Car> = [{id: 123, name: 'Tesla'}]

// 此处传入字符串'123'与id的number类型不匹配,目前仅能在运行时报错
console.log(checkIfStringIsDuplicated(dataArray, 'name', 'Tesla', 'id', '123'))

问题描述

该函数用于检查对象数组中是否存在指定字符串属性值重复的条目;若传入idKey和idValue,会忽略对应id的条目(适用于编辑场景)。当前存在的问题是:idKey与idValue的类型可能不匹配,目前仅能在运行时抛出错误提示,无法在编译阶段提前发现问题。


解决方案:通过泛型关联类型

我们可以调整泛型参数,让idValue的类型严格对应idKey在数据项中的属性类型,从而在编译阶段强制两者类型一致。修改后的函数如下:

/**
 * 检查字符串类型的值是否已存在于数据数组中
 * @param data 数据数组
 * @param key 要检查的字符串属性键
 * @param value 要检查的字符串值
 * @param idKey 用于排除自身条目的id属性键(可选)
 * @param idValue 对应idKey的属性值(可选)
 * @returns 如果值存在于数组中则返回true
 */
function checkIfStringIsDuplicated<T extends object, K extends keyof T>(
  data: T[],
  key: K,
  value: string,
  idKey?: keyof T,
  idValue?: idKey extends keyof T ? T[idKey] : never
): boolean {
  return !!data.find((item) => {
    // 确保要检查的属性是字符串类型(编译阶段约束)
    const itemValue = item[key];
    if (typeof itemValue !== 'string') return false;

    if (itemValue.trim().toLowerCase() === value.trim().toLowerCase()) {
      if (idKey !== undefined && idValue !== undefined) {
        // 此处类型已通过泛型关联,无需运行时类型检查
        return item[idKey] !== idValue;
      } else {
        return true;
      }
    } else {
      return false;
    }
  });
}

关键改进点

  • 泛型参数调整:使用T表示数据项的完整类型,K约束为T的键,确保key是数据项中存在的属性。
  • 类型关联:通过条件类型idKey extends keyof T ? T[idKey] : never,让idValue的类型严格对应idKey在T中的属性类型。
  • 编译阶段约束:新增对item[key]的类型检查,确保该属性是字符串类型,避免非字符串属性传入。

测试验证

interface Car {
  id: number;
  name: string;
}

const dataArray: Array<Car> = [{id: 123, name: 'Tesla'}]

// ✅ 正确用法:idValue为number类型,与id的类型匹配
console.log(checkIfStringIsDuplicated(dataArray, 'name', 'Tesla', 'id', 123));

// ❌ 编译阶段报错:类型'string'不能赋值给类型'number'
console.log(checkIfStringIsDuplicated(dataArray, 'name', 'Tesla', 'id', '123'));

这样就可以在编译阶段直接拦截idKey与idValue类型不匹配的问题,无需等到运行时才发现错误。


内容的提问来源于stack exchange,提问作者Konstantin Schütte

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 14:30:58