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

升级TypeScript后toArrayByObjectKey函数类型兼容问题求助

升级TypeScript后toArrayByObjectKey函数的类型错误解决方法

问题场景

升级TypeScript版本后,原有的toArrayByObjectKey函数出现编译错误,尝试官方提示的泛型约束方案后,测试代码又因Student类型缺少索引签名报错。相关代码及错误信息如下:

原函数代码

/**
 * For each instance of type `E` in the array argument
 * map the property values into arrays keyed by the name of the 
 * property in the instance of type `E`.
 * @param entities The array of entities
 * @return A single object with all the property values on the entities mapped into arrays.
 *
 * @example
students:Student[] = [
    {id:1, name:'1', sex:'X', standard: 1, propName: 11, anotherSillyPropName:111,},
    {id:2, name:'2', sex:'Y', standard: 2, propName: 22, anotherSillyPropName:222,},
    {id:3, name:'3', sex:'Z', standard: 3, propName: 33, anotherSillyPropName:333,},
]

console.log(toArrayByObjectKey(students))
*/
export function toArrayByObjectKey<E>(entities:E[]) {
    let res:any = {};

    for (let obj of entities)
        for (let [k, v] of Object.entries(obj))
            res[k] = (res[k] || []).concat(v)

    return res;
};

升级后编译错误

No overload matches this call.
  Overload 1 of 2, '(o: { [s: string]: unknown; } | ArrayLike<unknown>): [string, unknown][]', gave the following error.
    Argument of type 'E' is not assignable to parameter of type '{ [s: string]: unknown; } | ArrayLike<unknown>'.
      Type 'E' is not assignable to type 'ArrayLike<unknown>'.
  Overload 2 of 2, '(o: {}): [string, any][]', gave the following error.
    Argument of type 'E' is not assignable to parameter of type '{}'.ts(2769)
index.ts(237, 36): This type parameter might need an `extends ArrayLike<unknown>` constraint.
index.ts(237, 36): This type parameter might need an `extends { [s: string]: unknown; } | ArrayLike<unknown>` constraint.

尝试泛型约束后的测试错误

Error: projects/fs-collections/src/lib/src/index.spec.ts:154:41 - error TS2344: Type 'Student' does not satisfy the constraint '{ [s: string]: unknown; } | ArrayLike<unknown>'.
  Type 'Student' is not assignable to type '{ [s: string]: unknown; }'.
    Index signature for type 'string' is missing in type 'Student'.

154     let s:Students = toArrayByObjectKey<Student>(students);

解决方法

方案1:宽松约束+类型断言(快速修复)

给泛型E添加object约束,同时对Object.entries的参数做类型断言,绕过索引签名检查,无需修改Student类型:

export function toArrayByObjectKey<E extends object>(entities: E[]) {
    let res: Record<string, unknown[]> = {};

    for (let obj of entities)
        // 断言为带字符串索引的类型,满足Object.entries的类型要求
        for (let [k, v] of Object.entries(obj as Record<string, unknown>))
            res[k] = (res[k] || []).concat(v);

    return res;
};

方案2:精确返回类型(进阶优化)

使用TypeScript映射类型,让函数返回的对象类型与输入实体的属性严格对应,同时解决类型错误:

// 定义映射类型:将对象的每个属性转为对应类型的数组
type ObjectToArrays<T> = {
    [K in keyof T]: T[K][]
};

export function toArrayByObjectKey<E extends object>(entities: E[]): ObjectToArrays<E> {
    let res = {} as ObjectToArrays<E>;

    for (let obj of entities) {
        // 遍历对象键并断言为E的键类型,保证类型安全
        for (let k of Object.keys(obj) as Array<keyof E>) {
            const v = obj[k];
            res[k] = (res[k] || []) as E[typeof k][];
            res[k].push(v);
        }
    }

    return res;
};

这种方案下,toArrayByObjectKey(students)会返回类型为{id: number[], name: string[], sex: string[], ...}的对象,类型检查更严格。

方案3:为Student添加索引签名(不推荐)

如果允许修改Student类型定义,可以添加字符串索引签名,但会破坏类型的精确性:

interface Student {
    id: number;
    name: string;
    sex: string;
    standard: number;
    propName: number;
    anotherSillyPropName: number;
    // 添加索引签名
    [key: string]: unknown;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 18:15:29