如何在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 }
关键说明
- 泛型追踪:用
TrackedProps泛型参数记录已传入的属性键,每次调用后自动合并本次传入的属性键,TS能准确推导剩余可传入的属性。 - 参数限制:通过
Partial<Pick<State, RemainingProps>>确保后续参数只能包含未传入的属性,从类型层面禁止重复传参。 - 终止条件:当
RemainingProps为never(所有属性已传入),返回最终的完整状态类型,结束柯里化流程。
内容的提问来源于stack exchange,提问作者djuleAyo
相关产品推荐
相关产品推荐

