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

如何在TypeScript中为命名柯里化实现类型支持?

解决方案

核心思路是通过泛型追踪已传入的属性键集合,每次调用后更新这个集合,从而准确限制后续可传入的参数:

type FunctorState = {
  a: number;
  b: string;
  c: boolean;
};

// 命名柯里化类型:TrackedProps 记录已传入的属性键
type NamedCurry<State, TrackedProps extends keyof State = never> = 
  // 计算剩余待传入的属性键
  RemainingProps extends never 
    // 无剩余属性时,返回最终的完整State类型
    ? State 
    // 否则接收剩余属性的子集,返回更新TrackedProps后的柯里化函数
    : <Chunk extends Partial<Pick<State, RemainingProps>>>(
        chunk: Chunk
      ) => NamedCurry<State, TrackedProps | keyof Chunk>
  // 辅助类型:排除已传入的属性,得到剩余属性键
  where RemainingProps = Exclude<keyof State, TrackedProps>;

// 运行时实现:合并传入的分块参数
function createNamedCurry<State>(initialState: Partial<State> = {}): NamedCurry<State> {
  const currentState = { ...initialState };

  const curried = <Chunk extends Partial<State>>(chunk: Chunk): any => {
    Object.assign(currentState, chunk);
    // 检查是否已收集所有属性(可根据实际需求调整判断逻辑)
    const requiredKeys = Object.keys({} as State) as Array<keyof State>;
    const hasAllKeys = requiredKeys.every(key => key in currentState);
    
    if (hasAllKeys) {
      return currentState as State;
    }
    return curried;
  };

  return curried as NamedCurry<State>;
}

测试验证

const curryTest = createNamedCurry<FunctorState>();

// 第一次传入a:5,此时已追踪属性为"a",剩余属性为"b"|"c"
const step1 = curryTest({ a: 5 });

// ❌ TS直接报错:无法传入已存在的属性a
// const step2 = step1({ a: 3 });

// ✅ 正确传入剩余属性b
const step2 = step1({ b: "test" });

// ✅ 传入最后一个属性c,返回完整的FunctorState类型
const finalState = step2({ c: true });
console.log(finalState); // { a: 5, b: "test", c: true }

关键说明

  1. 泛型追踪:用TrackedProps泛型参数记录已传入的属性键,每次调用后自动合并本次传入的属性键,TS能准确推导剩余可传入的属性。
  2. 参数限制:通过Partial<Pick<State, RemainingProps>>确保后续参数只能包含未传入的属性,从类型层面禁止重复传参。
  3. 终止条件:当RemainingProps为never(所有属性已传入),返回最终的完整状态类型,结束柯里化流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 05:27:18