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

TypeScript中对象字面量内函数参数类型的推断问题

问题分析与解决

为什么类型推断失败?

你的代码存在循环类型依赖:

  • defineState的泛型T需要从StateDef<T>推断得出
  • 但StateDef<T>又依赖State<T>,而State<T>是基于T转换后的类型

这种双向循环的依赖关系超出了TypeScript类型推断的处理能力——TypeScript的类型推断是单向的,无法同时解决“从StateDef<T>推断T”和“用T计算State<T>再回传给StateDef<T>”这两个互相绑定的逻辑,最终导致fullName的state参数只能被推断为any。

可行的解决办法

我们可以调整类型定义逻辑,先定义最终的状态类型S,再推导对应的定义类型StateDef,彻底打破循环依赖:

方案1:反向约束泛型

type StateDef<S> = {
  [K in keyof S]: S[K] extends infer R ? R | ((state: S) => R) : never;
};

function defineState<S>(initialStateFn: () => StateDef<S>): S {
  const def = initialStateFn();
  const state = {} as S;
  // 核心实现:遍历定义对象,把函数执行结果赋值给最终状态
  for (const key in def) {
    const val = def[key];
    state[key] = typeof val === 'function' ? (val as (state: S) => S[typeof key])(state) : val;
  }
  return state;
}

// 使用示例
const state = defineState(() => ({
  name: 'John',
  surname: 'Doe',
  fullName: (state) => `${state.name} ${state.surname}`
}));

// 类型推断正常:state.fullName为string,state参数类型自动匹配最终状态类型

方案说明

这里直接将最终的状态类型S作为泛型参数,StateDef<S>表示“每个字段可以是最终值,或者接收最终状态并返回该字段值的函数”。TypeScript可以先从initialStateFn的返回值推断出S:普通字段直接取类型,函数字段则从返回值推断出S对应字段的类型,同时函数的state参数会被自动约束为S,完美解决循环依赖问题。

方案2:分离基础字段与计算字段

如果需要明确区分基础状态和计算状态,可以用双泛型参数拆分逻辑:

type BaseState = Record<string, unknown>;
type ComputedState<S extends BaseState> = {
  [K: string]: (state: S) => unknown;
};

function defineState<B extends BaseState, C extends ComputedState<B & { [K in keyof C]: ReturnType<C[K]> }>>(
  baseState: B,
  computed: C
): B & { [K in keyof C]: ReturnType<C[K]> } {
  const state = { ...baseState } as B & { [K in keyof C]: ReturnType<C[K]> };
  // 用getter绑定计算属性
  for (const key in computed) {
    Object.defineProperty(state, key, {
      get: () => computed[key](state)
    });
  }
  return state;
}

// 使用示例
const state = defineState({ name: 'John', surname: 'Doe' }, {
  fullName: (state) => `${state.name} ${state.surname}`
});

// 类型推断正常:state.fullName为string

这种写法通过拆分基础状态和计算状态,从根源上避免了循环依赖,同时保留了完整的类型推断能力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 04:46:22