TypeScript Mention --strictFunctionTypes and method/constructor exclusions in FAQ

j0pj023g  于 6个月前  发布在  TypeScript
关注(0)|答案(4)|浏览(48)

建议

🔍 搜索词

strictFunctionTypes bivariant interface FAQ

✅ 可实施性检查清单

我的建议符合以下准则:

  • 这不会对现有的TypeScript/JavaScript代码造成破坏性的更改
  • 这不会改变现有JavaScript代码的运行时行为
  • 这可以在不根据表达式的类型发出不同的JS的情况下实现
  • 这不是一个运行时特性(例如库功能,具有JavaScript输出的非ECMAScript语法,JS的新语法糖等)
  • 这个特性将与TypeScript's Design Goals的其他部分保持一致。

⭐ 建议

由于--strictFunctionTypes不适用于方法和构造函数,因此与function parameter bivariance相关的许多问题都无法解决。然而,FAQ中没有提到这个选项或例外情况。在没有指责或某种新鲜度属性的情况下,很难知道某些信息是否过时。Wiki - FAQ - 为什么函数参数是可变的?看起来一旦启用--strictFunctionTypes就不再适用,但它将会生效,而这将是有帮助的。

📃 激励示例

作为一名有经验的开发人员,我花了几个小时研究这个主题并阅读了相关的问题。甚至在返回并阅读更多内容之前,我还在撰写一个新的问题,最终将所有这些片段连接起来。

💻 用例

更快地让人们获得所需的完整知识。

w8ntj3qf

w8ntj3qf1#

在顶部提到:
https://github.com/microsoft/TypeScript/wiki/FAQ#common-bugs-that-aren't-bugs

  • 相同类型的方法和函数属性表现不同。
  • 方法在其参数上总是双变的,而函数属性在其参数上在 strictFunctionTypes 下是协变的。更多讨论 here
u91tlkcl

u91tlkcl2#

完全正确。我相当确定我读到了那部分内容。任何没有从顶部开始,而只是去 https://github.com/Microsoft/TypeScript/wiki/FAQ#why-are-function-parameters-bivariant 的人都会错过这一点。
对我来说,我可能将这个问题推到了我的认知栈上,因为我没有完全理解它的重要性。我不知道我在寻找函数和方法(也称为类函数)之间的区别。欣赏函数、方法和函数属性之间的区别是一个更深层次的主题,许多人可以长时间地忽略它。(在这个领域,我还有一些问题没有找到答案,也许是因为我不知道要搜索的正确术语。)当我找到“为什么函数参数是可变的”部分时,我花了很多精力试图理解它,但却失去了前面的部分——同时,Why部分说函数参数是可变的,并指出没有例外。我回到相关的问题中找到了 strictFunctionTypes 选项。
无论如何,这只是一个基于我的经验和观察的建议,问题似乎经常被提出。
顺便说一下,Why部分的逻辑问题有点晦涩难懂,至少对我来说是这样。有些问题假设读者已经了解了更多的信息。我认为这大部分是指 Array<T> 实现的具体细节,但在那里并没有提到。然后我认为有一些假设读者会知道 Array<T> 接口。

  • Dog[].push 是否可以分配给 Animal[].push ?
  • (x: Dog) => number 的类型是否可以分配给 (x: Animal) => number ?

push 检查是因为这是 Array<T> 的一种方法吗?(x: Dog/Animal) => number 检查是因为这是 push 的签名吗?对于逻辑的小提示,可以帮助读者:

  • Dog[].push 是否可以分配给 Animal[].push ?( pushArray<T> 上的一种方法)
  • (x: Dog) => number 的类型是否可以分配给 (x: Animal) => number ?( (x: T) => number)push 的签名。)

考虑到 strictFunctionTypes Pull request 的评论:
顺便说一下,请注意,尽管某些语言(如 C# 和 Scala)需要可变性注解(out/in 或 +/-),但由于 TypeScript 的结构类型系统,可变性实际上是从泛型类型中实际使用类型参数时自然产生的。
我原本不会期望 push 对于这个检查是必需的,因为 checkIfAnimalsAreAwake 不会修改数组,而且显然可以理解。(不确定在不查看实现的情况下如何做到这一点,但也许在那个时候实现已经被完全理解了。)

t3psigkw

t3psigkw3#

我相信FAQ条目使用Array作为论据的例子,因为双变元实际上只存在于确保类似数组的事物是协变的。最终我们得到了strictFunctionTypes,但方法被特别排除在外,以保持数组类型的协变性。换句话说,FAQ条目早于标志,应该重新编写(所以我们在这一点上达成了一致😄)。
checkIfAnimalsAreAwake不会修改数组,这显然是可以理解的。
从理论上讲这是正确的,但在这个例子中是不相关的;可分配性是两种类型之间的关系,如果没有排除变元,Array<Dog>将不会被分配给Array<Animal>,因为Array自己的T出现在输入位置(例如.push())。持有数组的代码是否行使这些输入并不重要,因为可分配性检查只关心涉及的类型,而不是绑定如何使用。解决这个问题的唯一方法是使用一个与数组兼容的类型作为checkIfAnimalsAreAwake的参数,但排除所有输入位置具有T的方法。

tp5buhyn

tp5buhyn4#

这段内容来自TypeScript官方文档的函数参数类型兼容性部分,其中提到:

当比较函数参数的类型时,如果源参数可以分配给目标参数,或者反之,赋值操作将成功。这种做法是不可靠的,因为调用者可能会最终得到一个接受更专门类型的函数,但使用较不专门类型的类型调用该函数。[...]

你可以通过编译器标志strictFunctionTypes让TypeScript在这种情况下引发错误。

我认为最后一句话“通过编译器标志strictFunctionTypes引发错误”需要明确指出这不适用于方法和构造函数。或者更好的做法是让它实际上与写的内容一致(并修复方法和构造函数,尽管我怀疑这可能需要一个单独的标志,如strictMethodTypes)。

虽然开发者被这个问题困扰时可以在报告bug之前查阅https://github.com/microsoft/TypeScript/wiki/FAQ#common-bugs-that-aren-t-bugs ,并意识到它的工作方式是预期的,但对于只阅读手册的开发者来说,在受到影响并开始报告bug之前了解这一点会更好。

另外,如果有一个严格性标志来应用到方法上,这将非常有用,因为通常在重构接口方法以接受更多类型时,不会意识到编译器会接受未更新的实现。我已经遇到过这种情况好几次。

相关问题