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函数
对象,它在字符串上被调用(即它有一个字符串作为其此
参数),并返回一个对象
然后编译器询问