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

TypeScript:如何让Reducer工厂优先依据返回值进行类型推断?

如何让TypeScript优先根据Reducer返回值推断类型?

问题背景

我有一个Reducer工厂函数,其返回值类型依赖于Reducer的返回值。最初的类型定义可以正确推断类型:

type SomeValue<T> = { value: T };

const fabric: <T extends () => any>(reducer: T) => SomeValue<ReturnType<T>> = (reducer) => {
  return { value: reducer() };
};

// 正确推断为 SomeValue<number>
const value1 = fabric(() => 1);

但当我修改Reducer,让它接收上一次的值时,类型推断出现问题。新的类型定义如下:

const fabric: <T>(reducer: (prev: undefined | T) => T) => SomeValue<T> = (reducer) => {
  let current: T | undefined = undefined;
  current = reducer(current);
  return { value: current };
};

显式指定参数类型时能正常工作:

// 正确推断为 SomeValue<number>
const value2 = fabric((prevValue: number = 1) => prevValue + 1);

但省略参数类型时,类型推断失效,结果变成SomeValue<unknown>:

// 错误推断为 SomeValue<unknown>,期望是 SomeValue<number>
const value3 = fabric((prevState = 1) => prevState);

解决方案

问题的根源是TypeScript的类型推断顺序:当参数类型定义为undefined | T时,TypeScript会优先从参数位置推断T,而无显式类型的参数只能推断为unknown。我们可以通过以下两种方式调整推断逻辑:

方案1:将参数改为可选类型(推荐)

把Reducer的参数定义为可选参数(prev?: T),它等价于prev: T | undefined,但TypeScript会结合参数的默认值优先推断T的类型:

type SomeValue<T> = { value: T };

const fabric: <T>(reducer: (prev?: T) => T) => SomeValue<T> = (reducer) => {
  let current: T | undefined = undefined;
  current = reducer(current);
  return { value: current };
};

// 正确推断为 SomeValue<number>
const value = fabric((prevState = 1) => prevState);

方案2:通过泛型约束绑定返回值与参数类型

使用泛型约束,让Reducer的返回值类型同时作为参数的类型之一,强制TypeScript优先从返回值推断类型:

type SomeValue<T> = { value: T };

const fabric = <R extends (prev: ReturnType<R> | undefined) => ReturnType<R>>(
  reducer: R
): SomeValue<ReturnType<R>> => {
  let current: ReturnType<R> | undefined = undefined;
  current = reducer(current);
  return { value: current };
};

// 正确推断为 SomeValue<number>
const value = fabric((prevState = 1) => prevState);

原理说明

  • 方案1利用了TypeScript对可选参数的推断逻辑:当可选参数有默认值时,TypeScript会将默认值的类型作为泛型T的候选类型,结合返回值的类型最终确定T。
  • 方案2通过泛型约束R extends (prev: ReturnType<R> | undefined) => ReturnType<R>,强制Reducer的参数类型必须是其返回值类型或undefined,从而让TypeScript优先从返回值推断ReturnType<R>,再反向约束参数类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 22:43:14