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

TypeScript通用统计计算器:如何基于mapper返回值推断calculator参数类型?

基于Mapper返回值自动推断Calculator参数类型的实现方案

核心思路是利用TypeScript的泛型特性,将每个统计项的mapper返回类型与calculator参数类型绑定,彻底消除手动类型断言的需求。

步骤1:定义泛型统计项类型

将原有的StatisticDefinition改为带泛型参数的类型,用泛型T表示mapper的返回值类型,让calculator的参数类型直接复用T:

type InputData = {
  foo: number[];
  bar: number[];
  baz: {
    qux: number;
  };
};

const input: InputData = {
  foo: [1, 2, 3],
  bar: [4, 5, 6],
  baz: {
    qux: 5,
  },
};

// 泛型版本的统计项定义,绑定mapper返回值与calculator参数类型
type StatisticDefinition<T> = {
  name: string;
  mapper: (input: InputData) => T;
  calculator: (mappedValue: T) => unknown;
};

步骤2:用辅助函数触发自动推断

直接定义对象无法让TypeScript为每个属性单独推断泛型,因此需要一个辅助函数来完成自动推断:

// 辅助函数,用于自动识别每个统计项的泛型类型
function createStatisticDefinitions<
  T extends Record<string, StatisticDefinition<any>>
>(defs: T) {
  return defs;
}

步骤3:编写统计项(无需类型断言)

使用辅助函数创建统计项集合,此时每个calculator的参数类型会自动匹配对应mapper的返回类型:

const statisticDefinitions = createStatisticDefinitions({
  averageFoo: {
    name: "Average Foo",
    mapper: (input) => input.foo,
    calculator: (foo) => {
      // foo自动推断为number[],无需as转换
      return foo.reduce((a, b) => a + b, 0) / foo.length;
    },
  },
  barPlusQux: {
    name: "Bar Plus Qux",
    mapper: (input) => [input.bar, input.baz.qux] as const,
    calculator: ([bar, qux]) => {
      // bar自动推断为number[],qux自动推断为number
      return bar.reduce((a, b) => a + b, 0) + qux;
    },
  },
});

提示:添加as const可以让mapper返回的数组类型更精确(从模糊的(number[] | number)[]变为明确的readonly [number[], number]),进一步提升类型安全性。

步骤4:执行逻辑保持不变

原有循环计算统计值的代码无需修改,类型检查依然有效:

for (const [key, statisticDefinition] of Object.entries(statisticDefinitions)) {
  const mappedValue = statisticDefinition.mapper(input);
  const calculatedValue = statisticDefinition.calculator(mappedValue);
  console.log(`${key} (${statisticDefinition.name}): ${calculatedValue}`);
}

扩展:明确统计结果类型

如果需要为每个统计项指定返回值类型,可以进一步扩展泛型:

type StatisticDefinition<TInput, TResult> = {
  name: string;
  mapper: (input: InputData) => TInput;
  calculator: (mappedValue: TInput) => TResult;
};

function createStatisticDefinitions<
  T extends Record<string, StatisticDefinition<any, any>>
>(defs: T) {
  return defs;
}

// 此时calculator的返回值类型也会被自动推断或手动指定
const statisticDefinitions = createStatisticDefinitions({
  averageFoo: {
    name: "Average Foo",
    mapper: (input) => input.foo,
    calculator: (foo): number => {
      return foo.reduce((a, b) => a + b, 0) / foo.length;
    },
  },
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 05:05:04