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

如何放宽泛型类型声明以避免推断出unknown类型

如何放宽泛型类型声明以避免推断出unknown类型

我太懂你遇到的这个痛点了——写了个带泛型的groupBy函数,正常场景下用得好好的,可一旦碰到隐式any类型的数组,TypeScript就把元素推断成unknown,导致属性访问直接报错。关键你还不想在每个调用处都加类型断言,改得麻烦死了对吧?咱们直接调整groupBy的泛型声明,就能完美解决这个问题,不用动任何调用代码。

先复盘下问题出在哪:
你原来的groupBy泛型参数ListValueType没有设置默认类型,在TypeScript的严格模式下,当传入的list是隐式any类型时,TypeScript会优先选择更安全的unknown作为推断结果,于是keyGetter里的elem就变成了unknown,自然没法访问myProperty这种属性。而如果你把所有类型都删掉,函数参数默认是any,反而不会有这个问题——本质就是我们需要让泛型在无法推断具体类型时, fallback 到any而非unknown。

直接上修改方案,只需要给ListValueType加个默认类型any就行,同时把KeyValueType的约束改成更规范的小写原始类型(原来的大写String/Number是构造函数类型,日常用原始类型更合适):

function groupBy<ListValueType = any, KeyValueType extends string | number>(
  list: ListValueType[],
  keyGetter: (elem: ListValueType) => KeyValueType
): Map<KeyValueType, ListValueType[]> {
  const map = new Map<KeyValueType, ListValueType[]>();
  list.forEach((item) => {
    const key = keyGetter(item);
    const collection = map.get(key);
    if (!collection) {
      map.set(key, [item]);
    } else {
      collection.push(item);
    }
  });
  return map;
}

咱们来验证下效果:

  1. 原来的正常类型调用完全不受影响,类型推断依然精准:
const arr = [1,2,3,4,5,6];
const map = groupBy(arr, x => x < 4 ? 'small' : 'large');
// map的类型还是Map<'small'|'large', number[]>,类型安全拉满
  1. 你之前报错的隐式any场景现在完全正常:
function someFunction(list) {
  // list是隐式any类型
  const map = groupBy(list, elem => elem.myProperty);
  // 再也不会出现TS18046错误了!elem会被推断为any
}

而且这种修改完全保留了原来的类型安全——当你传入明确类型的数组时,TypeScript依然会严格检查类型。比如你传一个带明确接口的对象数组,elem会自动推断为接口类型,属性拼写错了照样会报错:

interface User {
  role: string;
}
const users: User[] = [{role: 'admin'}, {role: 'user'}];
const userMap = groupBy(users, elem => elem.role);
// userMap的类型是Map<string, User[]>,完全符合预期

核心逻辑就是给泛型参数加默认值,让TypeScript在无法推断具体类型时,用any替代unknown,完美兼容你不想修改调用代码的需求。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 13:03:11