简体   繁体   English

使用 typescript generics 推断参数类型 function

[英]use typescript generics to infer type of param function

function validate<K>(validationFunc: (...args: (K extends Array<infer T> ? T : K)[]) => boolean, validationArgs: K[]): boolean {
  let res: boolean;
  for (const validationArg of validationArgs) {
    if (Array.isArray(validationArg)) {
      res = validationFunc(...validationArg);
    } else {
      // res = validationFunc(validationArg);
      res = (validationFunc as (args: K) => boolean)(validationArg);
    }
    if(!res) 
      return false;
  }
  return true
}

The commented line throws an Error at the argument: the Argument of type 'K' is not assignable to parameter of type 'K extends (infer T)[]? T: K'.ts(2345)注释行在参数处引发错误: the Argument of type 'K' is not assignable to parameter of type 'K extends (infer T)[]? T: K'.ts(2345) the Argument of type 'K' is not assignable to parameter of type 'K extends (infer T)[]? T: K'.ts(2345) , whereas the casted version works, and does not throw any errors. the Argument of type 'K' is not assignable to parameter of type 'K extends (infer T)[]? T: K'.ts(2345) ,而铸造版本可以工作,并且不会抛出任何错误。 As seen in this playground .正如在这个操场上看到的那样。

Why is typescript not able to infer, that on this line, K cannot be of type Array<any> and thus is allowed to be passed to the validation function?为什么 typescript 无法推断,在这一行上, K不能是Array<any>类型,因此允许传递给验证 function?

Semantically: If the second argument is of type K[] , the function needs to accept K as a single parameter.语义上:如果第二个参数的类型是K[] ,则 function 需要接受K作为单个参数。 If the second argument is of type K[][] , the function needs to accept multiple arguments of K .如果第二个参数的类型是K[][] ,则 function 需要接受多个 arguments 的K

Eg例如

validate((x: number) => x%2, [1, 2, 3]) should be ok validate((x: number) => x%2, [1, 2, 3])应该没问题

validate((a: string, b: string) => a === b, [['a', 'a'], ['b', 'b']]) should be ok validate((a: string, b: string) => a === b, [['a', 'a'], ['b', 'b']])应该没问题

validate((x: number) => x%2, ['a', 'b']) should throw an error validate((x: number) => x%2, ['a', 'b'])应该抛出一个错误

validate((x: number) => x%2, [['a', 'a'], ['b', 'b']]) should throw an error validate((x: number) => x%2, [['a', 'a'], ['b', 'b']])应该抛出一个错误

EDIT: validate((x: number) => x % 2 === 0, [[1, 2, 3]]) should also throw an error, since validate would destructure the number[][] once, and try to call (x: number) => boolean with number[]编辑: validate((x: number) => x % 2 === 0, [[1, 2, 3]])也应该抛出一个错误,因为 validate 会破坏number[][]一次,并尝试呼叫(x: number) => booleannumber[]

I don't think you need to infer the type of the param function.我认为您不需要推断参数 function 的类型。 Your validation arguments can be just K[] | K[][]您的验证 arguments 可以只是K[] | K[][] K[] | K[][] as you explained it. K[] | K[][]正如你所解释的那样。

I also did a small change when you call the validate function x % 2 should be wrapped in Boolean() otherwise the return value would be incorrect.当您调用 validate function x % 2时,我还做了一个小改动,应将其包裹在Boolean()中,否则返回值将不正确。

function validate<T extends (...args: any) => boolean, P extends Parameters<T>>(validationFunc: T, validationArgs: P[]): boolean {
  let res: boolean;

  for (const validationArg of validationArgs) {
    res = validationFunc(validationArg);
    if(!res) 
      return false;
  }
  return true
}

function simplified<T extends (...args: any) => boolean, P extends Parameters<T>>(validationFunc: T, validationArgs: P[]): boolean {
  return validationArgs.every((args) => validationFunc(args));
}

validate((x: number) => Boolean(x % 2), [[1], [2], [3]]) // should be ok

validate((a: string, b: string) => a === b, [['a', 'a'], ['b', 'b']]) // should be ok

validate((x: number) => Boolean(x % 2), [['a'], ['b']]) // should throw an error

validate((x: number) => Boolean(x % 2), [['a', 'a'], ['b', 'b']]) // should throw an error

validate((x: number) => x % 2 === 0, [[1, 2, 3]]); // should throw an error

Playground Link 游乐场链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM