Typescript错误';这';类型的上下文。。。不可分配给方法';s';这';类型

Typescript错误';这';类型的上下文。。。不可分配给方法';s';这';类型,typescript,Typescript,我目前正在调试一些库的代码,我一辈子都不理解一个特定的错误 下面是我正在调试的代码的简化示例: type Test1Type=object |((this:V)=>object); 函数testFnc(x:string,test1Fnc:Test1Type){ 让我们重新来过; if(test1Fnc的类型==“函数”){ res=test1Fnc.call(x,x); } } 在res=test1Fnc.call(x,x)行中术语test1Fnc被标记为错误: (parameter) tes

我目前正在调试一些库的代码,我一辈子都不理解一个特定的错误

下面是我正在调试的代码的简化示例:

type Test1Type=object |((this:V)=>object);
函数testFnc(x:string,test1Fnc:Test1Type){
让我们重新来过;
if(test1Fnc的类型==“函数”){
res=test1Fnc.call(x,x);
}
}
res=test1Fnc.call(x,x)行中术语
test1Fnc
被标记为错误:

(parameter) test1Fnc: Function | ((this: string) => object)

The 'this' context of type 'Function | ((this: string) => object)' is not assignable to method's 'this' of type '((this: string) => object) & Function'.
  Type 'Function' is not assignable to type '((this: string) => object) & Function'.
    Type 'Function' is not assignable to type '(this: string) => object'.
      Type 'Function' provides no match for the signature '(this: string): object'.ts(2684)
.call()
的内部类型定义如下:

调用(this:(this:T,…args:A)=>R,thisArg:T,…args:A):R

不幸的是,我无法找出这段代码的错误,特别是因为我正在调试的库的代码库()中直接有这段代码

我真的不明白这里的错误消息告诉了我什么

我正在使用
“typescript”:“~3.9.3”
(库正在使用
“typescript”:“^2.8.3”


非常感谢您的帮助,因为我很想了解这里发生了什么。

您发现TypeScript处理
函数
和联合类型交互的方式不一致

编译器做什么 调用
call
时,编译器知道
test1Fnc
是:

  • 具有未知签名的JavaScript
    函数
    对象,或
  • 一个JavaScript
    函数
    对象,它在字符串上被调用(即它有一个字符串作为其
    参数),并返回一个对象
  • 然后,编译器会询问该调用对于这些类型中的每一种是否有效

    当它询问该调用是否对类型1有效时,它得出结论认为该调用无效,因为
    test1Fnc
    可能无法对字符串调用

    为什么这很奇怪 这很奇怪,因为这与
    Function
    对象的常规TypeScript行为相反,后者通常允许任何类型的函数调用。要查看是否允许此类调用,请临时将初始类型声明更改为
    type Test1Type=object
    ,错误就会消失

    之所以出现这种情况,是因为编译器处理
    函数
    类型的两个方面是正确的:

  • 任何类型的函数调用都是允许的,但是
  • 它们不能分配给具有指定参数的函数
  • 当编译器知道
    test1Fnc
    只是一个
    函数
    时(当类型声明被更改时),它会根据规则1工作。但是当涉及联合类型时,它首先尝试将联合类型分配给
    调用的给定签名。在规则1有机会覆盖它之前,由于规则2,该分配失败

    为什么编译器不应该这样做 您可以看到这不是预期的行为,因为如果
    Test1Type
    被定义为这两种类型中的任意一种(前提是进行了下一节中解释的修改),那么编译器不会给出任何错误。这是不对的:如果通过程序的路径对联合类型中的任何一种类型都有效,那么程序应该对联合类型有效

    但无论如何,这种类型是错误的 另一个观察结果是,即使
    test1Fnc
    是上面提到的类型2,设置的
    call
    函数也不能调用它。给定的
    调用
    函数需要一个
    this
    字符串
    ,以及一个
    字符串
    类型的常规参数,但是上面的类型2只是一个
    this
    字符串
    类型的值,没有常规参数。编译器目前没有显示此错误,但是如果将初始类型声明更改为
    typetest1type=((this:V)=>object)
    ,则会看到产生不同的错误。反过来,通过将行更改为
    typetest1type=((this:V,arg:V)=>object)
    可以消除这种情况

    建议:重新定义、强制转换、报告和不使用联合 处理这个问题,你可以考虑以下一个或多个:

  • 重新定义
    Test1Type=object |((this:V,arg:V)=>object)
    ,这似乎是代码所期望的。这并没有真正改变类型,因为它仍然可以是任何对象,但它确实更好地表达了代码的意图
  • 然后,为了清除错误,如果可以将
    if
    块中的
    test1Fnc
    类型强制转换为预期类型:
    res=(test1Fnc as(this:string,arg:string)=>object)。调用(x,x)
    。如果您无法进行这样的更改,则可能必须放弃任何类型安全性,转而使用
    type Test1Type=object
  • 您可能希望在TypeScript GitHub上报告此问题。我不确定这是否是他们的优先事项,因为可能不鼓励使用
    函数
    对象进行键入,而且
  • 无论如何,我不鼓励使用这种联合类型。它是如此普遍,在任何情况下都不能真正实现类型安全性。目前尚不清楚您对代码的控制程度,以及可能需要哪些其他值
    Test1Type
    ,但如果您可以进行更广泛的更改,则最好将其编写为更显式类型的联合,以便编译器可以在它们之间进行选择,或者以完全OOP风格更严格地设置类层次结构

  • 您发现TypeScript处理
    函数
    和联合类型交互的方式不一致

    编译器做什么 调用
    call
    时,编译器知道
    test1Fnc
    是:

  • 具有未知签名的JavaScript
    函数
    对象,或
  • 一个JavaScript
    函数
    对象,它在字符串上被调用(即它有一个字符串作为其
    参数),并返回一个对象
  • 然后编译器询问