如何在TypeScript中为命名咖喱提供类型支持



定义:命名咖喱

  • 命名部分表示函数在单个对象中接受其所有参数。有点像python的参数。通过这种方式,我可以通过名称规范在任何排列中指定参数,并强制函数的用户知道名称
  • 这个对象可以一块一块地传递,直到收集到所有道具为止-咖喱部分
/*
* Goal: Named curry with type support
*
*/

type FunctorState = {
a: number;
b: string;
c: boolean;
}
/**
* Here all keys get removed and it's kind of ok since we have no concretization
* of partial
*/
type Test<T> = Omit<T, keyof Partial<T>>;
type NamedCurry<
State, 
Chunk extends Partial<State> = Partial<State>, 
REST = Omit<State, keyof Chunk>
> = (a: Chunk) => NamedCurry<REST>;

const curryTest: NamedCurry<FunctorState> = a => {
//disregart the implementation it's runtime anyways...
const a_construction = a;
return curryTest;
}
/**
* Here still all the keys get removed which sucks! Type deduction should insert
* typeof {a: 5} and then this could work
*/
const curryConcreteStep1 = curryTest({
a: 5,
});
const curryConcreteStep2 = curryConcreteStep1({
a: 3
})

有人知道热解决这个问题吗

感谢您提出有趣的问题。我还包含了一个终端状态(所有参数都已用尽)和忽略未定义的值。

我想出了这个解决方案:

type Arguments = {
[index: string | number | symbol]: any
}
type FunctorState = {
a: number;
b: string;
c: boolean;
}
type IgnoreUndefined<T extends Partial<Arguments>> = {
[Key in keyof T as T[Key] extends undefined ? never: Key]: T
}
type Remainder<Full extends Arguments, Args extends Partial<Full>> = Omit<Full, keyof IgnoreUndefined<Args>>
type Curried<Full extends Arguments, R> = <T extends Partial<Full>>(args: T) => (keyof Remainder<Full, T> extends never ? R : Curried<Remainder<Full, T>, R>)
const curriedTest: Curried<FunctorState, string> = (args) => undefined!! // don't care, not about the implementation of this thing
const step1 = curriedTest({a: 2})
const unchanged = step1({b: undefined})
const step2 = unchanged({b: "test", c: true})

作为一个有趣的旁注。也可以将其扩展到部分内部的部分,方法是在定义的部分上抛出另一个映射并调整它们的值,一旦它们的值降低到终端状态,就抛出它们的键。

最新更新