为部分应用程序使用TypeScript

为部分应用程序使用TypeScript,typescript,Typescript,我喜欢使用对象文字作为函数参数,因为它允许我标记参数名称。我认为有一种类型安全的通用方法可以对这些类型的函数应用部分函数。假设一个函数接受一个类型为X的参数,然后我通过另一个名为“partial”的函数运行该函数,在这里我提供了X的一部分,它可以返回一个新函数,该函数只需要缺少的值。下面的例子最容易看到。这里的好处是,通过我的“partial”函数,我可以提供任意数量或参数组合,并得到一个结果函数,该函数清楚地指出仍然需要什么 function partial<Args, Fixed ex

我喜欢使用对象文字作为函数参数,因为它允许我标记参数名称。我认为有一种类型安全的通用方法可以对这些类型的函数应用部分函数。假设一个函数接受一个类型为X的参数,然后我通过另一个名为“partial”的函数运行该函数,在这里我提供了X的一部分,它可以返回一个新函数,该函数只需要缺少的值。下面的例子最容易看到。这里的好处是,通过我的“partial”函数,我可以提供任意数量或参数组合,并得到一个结果函数,该函数清楚地指出仍然需要什么

function partial<Args, Fixed extends Partial<Args>, Result>(fn: (args: Args) => Result, fixed: Fixed) {
    type Unspecified = { [P in Exclude<keyof Args, keyof Fixed>]: Args[P] };
    const result = (args: Unspecified) => {
        const combined = {};
        Object.assign(combined, fixed, args);
        return fn(combined as Args);
    };
    return result as ({} extends Unspecified ? () => Result : (args: Unspecified) => Result);
}

interface AddThreeNumbersArgs {
    a: number;
    b: number;
    c: number;
    caption: string;
}

function addThreeNumbers(args: AddThreeNumbersArgs) {
    return `${args.caption} ${args.a + args.b + args.c}`;
}

test("fix one number and the caption", () => {
    const f = partial(addThreeNumbers, { b: 10, caption: "The answer is:" });
    const result = f({ a: 1, c: 25 });
    expect(result).toBe("The answer is: 36");
});

我想你已经遇到了这个问题;TypeScript对涉及的类型推断没有很好的支持。更新:不幸的是,TS3.4中添加的对的支持不够全面,无法在这里帮助您;编译器现在可以将一些泛型类型参数从输入函数传播到输出函数(例如,如果
concatenate
是泛型的,那么
partial(concatenate,…)
也将是泛型的),但它不能在输入函数中任意指定泛型类型参数(例如,插入
number
作为
concatenate
中的类型参数,以使输出函数非泛型)。因此,例如,仍然是设计限制

我能想到的唯一解决方法是在某个地方显式指定类型。例如,可以将回调函数的秩降低为非泛型,如:

const f = partial(
  concatenate as (x: ConcatenateArrayArgs<number>)=>number, 
  { first: [1, 2, 3] }
);

这两种方法都有效,但并不特别令人满意。希望这至少为您指明了正确的方向。祝您好运!

链接GitHub问题在2019年解决,当时他们添加了对更高级别函数类型的支持:谢谢!不幸的是,该功能不支持此处的用例,但我已更新了答案以反映这一点。
const f = partial(
  concatenate as (x: ConcatenateArrayArgs<number>)=>number, 
  { first: [1, 2, 3] }
);
const r = partial<
  ConcatenateArrayArgs<number>,
  { first: number[] },
  number[]
>(concatenate, { first: [1, 2, 3] });