typescript-typings - 在需要函数的地方,打字稿允许我传递具有不兼容的“应用”属性的对象
问题描述
目前使用 typescript 3.4.5并strict
启用模式...
背景故事
不幸的是,我刚刚遇到了打字稿无法保护我免受错误的情况。我试图弄清楚为什么打字稿未能捕捉到这个错误。
我正在为这样的函数编写类型声明:
function acceptVisitors (visitor) {
visitor.apply(value);
}
精明的观察者可能会指出visitor
's 的类型可以通过以下两种方式之一定义——作为函数,或者作为具有apply
属性的对象:
type visitorType = (this: IValue) => void;
// or
type visitorType = {
apply: (value: IValue) => void;
};
事实证明,在我的情况下是后者。添加类型声明后,我继续编写此错误代码:
// This is incorrect because it doesn't pass it as an argument.
// Rather, the `this` context is set to the value.
acceptVisitors((value: IValue) => { ... });
现在,令人费解的是,当我传递一个类型不兼容的函数时,Typescript 没有显示错误visitorType
。
简化示例
让我们将参数类型更改为字符串,然后遍历它。
我正在定义一个名为的类型func
,它是一个需要字符串参数的函数。
type func = (param1: string) => void;
函数本质上是具有应用方法的可调用对象。
declare let f: func;
f.apply(undefined, ['str']);
// all good
现在是另一种类型——具有apply
属性的对象。
type objectWithApplyProp = {
apply: (param1: string) => void;
};
我们可以调用 apply 属性,但方式不同......
declare let o: objectWithApplyProp;
o.apply(undefined, ['str']); // Error: Expected 1 arguments, but got 2.
并且objectWithApplyProp
有一个不适用的呼叫签名func
:
o.apply('str'); // ok
f.apply('str'); // Error: The 'this' context of type 'func' is not assignable to
// method's 'this' of type '(this: string) => void'
进一步的测试表明它f
可以分配给o
,但不是相反,这是有道理的……所有函数都是对象,但并非所有对象都是可调用的。
但是为什么被f
认为可以分配给o
?的类型objectWithApplyProp
需要一个与特定类型apply
匹配的值,但不匹配func
一个函数的apply
签名应该可以从它的参数中推断出来,但打字稿似乎并没有推断出它。
因此,欢迎任何反馈。我错了,还是打字稿有限制?这是一个已知问题吗?谢谢
解决方案
因此,这是发生这种情况的技术原因,也是一种解决方法:
Typescript 的内置lib/es5.d.ts声明文件定义Function.apply
了 type 的参数any
。它也定义Function.prototype
为`any。
interface Function {
apply(this: Function, thisArg: any, argArray?: any): any;
call(this: Function, thisArg: any, ...argArray: any[]): any;
bind(this: Function, thisArg: any, ...argArray: any[]): any;
toString(): string;
prototype: any;
readonly length: number;
// Non-standard extensions
arguments: any;
caller: Function;
}
我猜所有的函数表达式都Function
默认给出了类型。
因此,允许将函数分配给具有不兼容apply
属性的对象,因为该函数没有apply
基于内置Function
类型的强类型方法。因此打字稿无法确定apply
签名不同。
Typescript 3.2引入了CallableFunction,它在其apply
声明中具有通用参数。但我还没有想出如何让它解决这个问题。
一种解决方法是定义更强的函数类型并手动将其分配给函数。解决方法有点乏味,但它有效。
interface func extends Function {
(param1: string): void;
// manually define `apply
apply<T, R> (thisArg: T, args: [string]): R;
}
interface objectWithApplyProp { // unchanged
apply: (param1: string) => void;
}
// Now we have proper errors here:
o = f;
// Type 'func' is not assignable to type 'objectWithApplyProp'.
// Types of property 'apply' are incompatible.
// Type '<T, R>(thisArg: T, args: [string]) => R' is not assignable to type '(param1: string) => void'. ts(2322)
f = o;
// Type 'objectWithApplyProp' is missing the following properties from type 'func': call, bind, prototype, length, and 2 more. ts(2740)
推荐阅读
- css - 如何扩大输入书写区域?
- android-studio - 您好,有人在您的 Flutter 项目中成功添加了蓝牙 CPCL 吗?
- r - 如何制作具有两个显示比例的分类变量的分组条形图?
- python - 过滤包含非 ascii 值的 pandas 数据帧行
- python - datetime.strptime 给了我错误的月份
- python - 如何在两个函数中传递一个值而不显示错误?
- webstorm - JetBrains 如何在 WebStorm IDE 上打开多项目
- javascript - 在 vue 组件中添加 html
- javascript - 在 nodejs 中添加新/替换元素
- python - 使用 Python 和 pandas 计算两个日期之间的 Delta