Typescript 从具有泛型类型的对象索引调用函数

Posted

技术标签:

【中文标题】Typescript 从具有泛型类型的对象索引调用函数【英文标题】:Typescript invoke function from object index with generic type 【发布时间】:2019-08-23 01:30:11 【问题描述】:

我正在尝试在 Typescript 中使用泛型,将泛型参数用作索引来调用存储在对象中的函数。 我收到的错误是:

[ts] 无法调用类型缺少调用签名的表达式。输入 '((变量: insertId: number; ) => string) | ((变量: updateId:数字;值:字符串;)=>字符串)| ((variable: deleteId: number; ) => string)' 没有兼容的调用签名。 [2349]

'QueryInput[T]' 类型的参数不能分配给' insertId: number; 类型的参数。 & updateId: number;值:字符串; & deleteId: number; '。 键入' insertId:数字; | updateId:数字;值:字符串; | deleteId:数字; ' 不可分配给类型 ' insertId: number; & updateId: number;值:字符串; & deleteId: number; '。 键入' insertId:数字; ' 不可分配给类型 ' insertId: number; & updateId: number;值:字符串; & deleteId: number; '。 键入' insertId:数字; ' 缺少来自类型 ' updateId: number; 的以下属性值:字符串; ':updateId,值 类型 'QueryInput[T]' 不可分配给类型 ' insertId: number; '。 键入' insertId:数字; | updateId:数字;值:字符串; | deleteId:数字; ' 不可分配给类型 ' insertId: number; '。 ' updateId: number; 类型中缺少属性 'insertId'值:字符串; ' 但在 ' insertId: number; 类型中是必需的'.ts(2345) App.tsx(7, 13): 'insertId' 在这里声明。 (参数)变量:QueryInput[T]

这是一个复制问题的示例代码:

type Query = "insert" | "update" | "delete";

interface QueryInput 
  insert:  insertId: number ;
  update:  updateId: number; value: string ;
  delete:  deleteId: number ;


type QueryObject =  [T in Query]: (variable: QueryInput[T]) => string ;

const queries: QueryObject = 
  insert: variable => "insert",
  update: ( updateId, value ) => "update",
  delete: variable => "delete"
;

const getQuery = <T extends Query>(query: T, variables: QueryInput[T]) => 
  return queries[query](variables); // this line throws an error

Typescript 引擎似乎无法解析函数的正确签名 - 尽管肯定只有 1 个可能的签名(从 queries[query] 返回的那个)。 看来queryvariables 已正确解析,并且具有适当的类型。

【问题讨论】:

它无法推断variables 的类型,因为query 的值只有在运行时才知道。因此 TypeScript 无法推断出 queries[query] 是什么,因此它假定它是所有可能的类型,但随后您声明 variables 只能是其中一种类型,它不知道是哪一种。 就像我写的那样,查询和变量正确解析了。 【参考方案1】:

如果您想要一个快速的肮脏解决方案来使其编译,

const getQuery = <T extends Query>(query: T, variables: QueryInput[T]) => 
  let v: any = variables;
  return queries[query](v); // this line doesnt throw an error

这并不理想,但 getQuery 本身似乎不需要改变。 并且 getQuery 的使用仍将根据您的需要在此解决方案中输入,只是它的实现不会。

直到你找到更好的解决方案..

【讨论】:

它也不起作用。它会在运行时引发相同的错误。 谢谢!我不得不升级打字稿(我有 3.2.4、3.4.1 的工作),你的解决方案成功了。

以上是关于Typescript 从具有泛型类型的对象索引调用函数的主要内容,如果未能解决你的问题,请参考以下文章

Typescript - 具有通用类型函数的索引签名

TypeScript,啥是对象文字的调用签名以及它们如何与泛型类型一起使用?

Typescript - 确保泛型属性存在于具有描述性错误的泛型类型上

在 TypeScript 中,如何在具有多个类型参数的方法中推断出泛型类型参数?

TypeScript - 如何将索引签名表示为泛型类型

Object.keys 迭代导致 Typescript 错误“元素隐式具有‘任何’类型,因为索引表达式不是‘数字’类型”