验证同一个参数可以调用一个参数(它是一个函数)

时间:2018-07-23 19:46:11

标签: typescript typescript-typings

我正在编写一些高阶函数,发现很难编写类型来验证可以将提供的函数作为自变量提供的其他自变量调用的类型。这是一个超级基本的示例:

function(myFunc, arg1, arg2) {
    return myFunc(arg1, arg2) // We want to verify that this is typesafe at compile time
}

还有一个更现实的例子:

// Here's a higher order function that returns a function that alters input in some way
type algorithm = (input: number, options?: any) => number;
const createHandler = (algorithm: algorithm, options?) =>
  (input: number) => algorithm(input, options);

// This algorithm needs no 'options' configuration
const addOne = (input) => input + 1;
// This algorithm requires a specific 'options' configuration
interface PowerOptions { value: number; }
const power = (input: number, {value}: PowerOptions) => input ** value

// Now when I create these handlers, I'd like for the 'options' to be validated against the provided function
const addOneHandler = createHandler(addOne);
const squaredHandler = createHandler(power, { value: 2 });
const cubedHandler = createHandler(power, {});  // This should show a type error as the options are invalid for the algorithm

1 个答案:

答案 0 :(得分:1)

关于您的基本示例,可以通过类型推断进行这种方式,以检查所提供函数(check it on Typescript Playground)的类型安全性:

const a = function <U, V>(myFunc: (arg1: U, arg2: V) => any, arg1: U, arg2: V) {
    return myFunc(arg1, arg2)
}

const doubleIfTrue = (arg1: number, arg2: boolean) => arg2 ? 2 * arg1 : arg1

console.log(a(doubleIfTrue, 1, true))  // Type OK
console.log(a(doubleIfTrue, 1, "hop")) // Wrong type: number and string provided

在这种情况下,根据提供的函数的参数推断出UV类型。


但是您想要实现的目标会变得更加复杂。根据您的代码,我可以进行一些整理(check it on Typescript Playground):

type algorithm<OPT = null> = (input: number, options?: OPT) => number;
type algorithmOptions<A> = A extends algorithm<infer OPT> ? OPT : null

const createHandler = <A extends algorithm<any>>(algorithm: A, options: algorithmOptions<A>) =>
(input: number) => algorithm(input, options);

// Algorithms
const addOne:algorithm = (input: number) => input + 1;
interface PowerOptions { value: number; }
const power:algorithm<PowerOptions> = (input: number, {value}) => input ** value

// Handlers
const squaredHandler = createHandler(power, { value: 2 }); // correct
const addOneHandler = createHandler(addOne, null); // correct if a second argument is provided

const addOneHandlerFailing = createHandler(addOne, { value: 2 }); // wrong because an argument is provided
const squaredHandlerFailing1 = createHandler(power, {}); // wrong because of argument interface not respected
const squaredHandlerFailing2 = createHandler(power); // wrong because no argument provided

使用一些conditional type来检索算法参数。但是也许我走得太远了,您可以找到一种更简单的方法

另一件事:据我所知,createHandler的options参数在某些情况下可能不是可选的,而在另一些情况下则不是必需的,而无需将示例变得更复杂。

希望对您有帮助!