问题背景
默认情况下,TypeScript在函数类型签名的匹配方面允许一定的“宽松性”,允许可逆和不可逆的函数被视为兼容。从TypeScript 2.6开始,引入了strictFunctionTypes选项,确保对函数类型进行严格检查,并防止许多类型错误,尤其是在大型代码库中。
问题
在没有严格检查的情况下,可能会出现函数处理程序或回调接受更多或更具体的参数类型,而对此开发者并不知情。这会导致与返回类型的协变性和参数的逆变性相关的运行时错误。
解决方案
strictFunctionTypes选项为函数参数类型引入了严格的逆变性。现在,只有当源类型的参数是目标参数的超类型时,函数才被认为是兼容的,而反之则不然。
代码示例:
type Animal = { name: string }; type Cat = { name: string; meow: () => void }; let animalHandler: (a: Animal) => void; let catHandler: (c: Cat) => void; animalHandler = catHandler; // 在strictFunctionTypes下会报错:参数过于具体 catHandler = animalHandler; // 允许,Cat是Animal的子类型
关键特性:
在strictFunctionTypes出现之前,是否可以将更具体类型的处理程序分配给函数?
是的,在没有激活strictFunctionTypes之前,TypeScript允许将更具体的函数分配给通用函数,这会导致运行时问题:
enum E { A, B } const f: (e: E) => void = (e: E.A) => {} // 在没有strictFunctionTypes下:允许
strictFunctionTypes如何影响具有可选参数的回调?
如果函数回调的参数使某些参数成为可选参数,则严格检查将不允许在期待多个必填参数的地方使用少量必填参数的函数。这可以防止callback未获得所需数据的情况。
在旧项目中启用strictFunctionTypes会出现兼容性问题吗?
是的,存在出现新编译错误的风险,因为许多函数和处理程序可能以逆变性不匹配的方式相互分配。这通常出现在回调或使用第三方库API而没有严格类型时。
在一个大型项目中,事件处理程序接受更具体的类型(MouseEvent而不是通用Event)。在启用严格选项之前,这并不会被发现,导致在与不同事件源运行时出现错误。
优点:
缺点:
该项目一开始就使用strictFunctionTypes。在添加新的处理程序时,所有类型之间的不一致都会自动被编译器发现。代码对于拼写错误变得更稳定,维护起来更简单。
优点:
缺点: