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

如何为数组+reduce函数的动态字典正确添加类型?

为动态添加的Reducers实现类型安全的字典

问题分析

你当前的reducers字段使用Record<string, Reducer<unknown, unknown>>虽然允许动态添加,但丢失了每个key对应Reducer的具体类型信息,也无法在编译时自动推断后续操作的类型。我们需要一种既能支持动态添加,又能保证单个Reducer内部T和U一致性,同时跟踪整体结构类型的方案。

解决方案:泛型类跟踪Reducers结构

通过让Part类接受泛型参数来跟踪reducers的具体结构,每次添加Reducer时自动细化类型:

// 修正原类型中的拼写错误:initalValue -> initialValue
type ReduceFn<T, U> = (result: U, nextValue: T, index: number) => U;
type Reducer<T, U> = { array: T[]; reducefn: ReduceFn<T, U>; initialValue: U };

class Part<R extends Record<string, Reducer<any, any>> = {}> {
  indices: number[];
  reducers: R;

  constructor(indices: number[]) {
    this.indices = indices;
    this.reducers = {} as R;
  }

  addReducer<K extends string, T, U>(
    key: K,
    reducer: Reducer<T, U>
  ): Part<R & Record<K, Reducer<T, U>>> {
    // 合并原有reducers与新reducer,并断言为更新后的类型
    this.reducers = { ...this.reducers, [key]: reducer } as R & Record<K, Reducer<T, U>>;
    return this as Part<R & Record<K, Reducer<T, U>>>;
  }

  // 示例:获取归约后的值(子集化逻辑可自行补充)
  getReducedValue<K extends keyof R>(key: K): ReturnType<R[K]['reducefn']> {
    const { array, reducefn, initialValue } = this.reducers[key];
    // 此处加入你已实现的数组子集化逻辑,比如:
    // const subset = array.filter((_, idx) => this.indices.includes(idx));
    return array.reduce(reducefn, initialValue);
  }
}

使用示例

// 初始化实例,reducers为空
const part = new Part([0, 2]);

// 添加第一个Reducer,实例类型自动更新
const partWithSum = part.addReducer('sum', {
  array: [1, 2, 3, 4],
  reducefn: (acc, val) => acc + val,
  initialValue: 0
});

// 添加第二个Reducer,类型继续细化
const partWithSumAndJoin = partWithSum.addReducer('join', {
  array: ['a', 'b', 'c', 'd'],
  reducefn: (acc, val) => acc + val,
  initialValue: ''
});

// 自动推断返回值类型
const sum = partWithSumAndJoin.getReducedValue('sum'); // sum: number
const joined = partWithSumAndJoin.getReducedValue('join'); // joined: string

// 编译时错误:访问不存在的key
partWithSumAndJoin.getReducedValue('invalid'); // 类型提示:"invalid"不在"sum" | "join"中

简化方案(牺牲部分类型安全)

如果不需要跟踪每个key的具体类型,仅需保证单个Reducer内部类型一致,可以保留原结构但优化addReducer的泛型约束:

type ReduceFn<T, U> = (result: U, nextValue: T, index: number) => U;
type Reducer<T, U> = { array: T[]; reducefn: ReduceFn<T, U>; initialValue: U };

class Part {
  indices: number[];
  reducers: Record<string, Reducer<unknown, unknown>>;

  constructor(indices: number[]) {
    this.indices = indices;
    this.reducers = {};
  }

  addReducer<T, U>(key: string, reducer: Reducer<T, U>) {
    this.reducers[key] = reducer;
    return this;
  }

  // 获取值时需手动指定类型或断言
  getReducedValue<T, U>(key: string): U {
    const reducer = this.reducers[key] as Reducer<T, U>;
    const subset = reducer.array.filter((_, idx) => this.indices.includes(idx));
    return subset.reduce(reducer.reducefn, reducer.initialValue);
  }
}

这种方案实现简单,但调用getReducedValue时需要手动传入类型,存在误写风险,适合对类型安全要求不高的场景。

内容的提问来源于stack exchange,提问作者Adam B.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 16:47:46