建议
🔍 搜索词
strictFunctionTypes bivariant interface FAQ
✅ 可实施性检查清单
我的建议符合以下准则:
- 这不会对现有的TypeScript/JavaScript代码造成破坏性的更改
- 这不会改变现有JavaScript代码的运行时行为
- 这可以在不根据表达式的类型发出不同的JS的情况下实现
- 这不是一个运行时特性(例如库功能,具有JavaScript输出的非ECMAScript语法,JS的新语法糖等)
- 这个特性将与TypeScript's Design Goals的其他部分保持一致。
⭐ 建议
由于--strictFunctionTypes
不适用于方法和构造函数,因此与function parameter bivariance相关的许多问题都无法解决。然而,FAQ中没有提到这个选项或例外情况。在没有指责或某种新鲜度属性的情况下,很难知道某些信息是否过时。Wiki - FAQ - 为什么函数参数是可变的?看起来一旦启用--strictFunctionTypes
就不再适用,但它将会生效,而这将是有帮助的。
📃 激励示例
作为一名有经验的开发人员,我花了几个小时研究这个主题并阅读了相关的问题。甚至在返回并阅读更多内容之前,我还在撰写一个新的问题,最终将所有这些片段连接起来。
💻 用例
更快地让人们获得所需的完整知识。
4条答案
按热度按时间w8ntj3qf1#
在顶部提到:
https://github.com/microsoft/TypeScript/wiki/FAQ#common-bugs-that-aren't-bugs
strictFunctionTypes
下是协变的。更多讨论 here 。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
?(push
是Array<T>
上的一种方法)(x: Dog) => number
的类型是否可以分配给(x: Animal) => number
?((x: T) => number)
是push
的签名。)考虑到
strictFunctionTypes
Pull request 的评论:顺便说一下,请注意,尽管某些语言(如 C# 和 Scala)需要可变性注解(out/in 或 +/-),但由于 TypeScript 的结构类型系统,可变性实际上是从泛型类型中实际使用类型参数时自然产生的。
我原本不会期望
push
对于这个检查是必需的,因为checkIfAnimalsAreAwake
不会修改数组,而且显然可以理解。(不确定在不查看实现的情况下如何做到这一点,但也许在那个时候实现已经被完全理解了。)t3psigkw3#
我相信FAQ条目使用
Array
作为论据的例子,因为双变元实际上只存在于确保类似数组的事物是协变的。最终我们得到了strictFunctionTypes
,但方法被特别排除在外,以保持数组类型的协变性。换句话说,FAQ条目早于标志,应该重新编写(所以我们在这一点上达成了一致😄)。checkIfAnimalsAreAwake
不会修改数组,这显然是可以理解的。从理论上讲这是正确的,但在这个例子中是不相关的;可分配性是两种类型之间的关系,如果没有排除变元,
Array<Dog>
将不会被分配给Array<Animal>
,因为Array
自己的T
出现在输入位置(例如.push()
)。持有数组的代码是否行使这些输入并不重要,因为可分配性检查只关心涉及的类型,而不是绑定如何使用。解决这个问题的唯一方法是使用一个与数组兼容的类型作为checkIfAnimalsAreAwake
的参数,但排除所有输入位置具有T
的方法。tp5buhyn4#
这段内容来自TypeScript官方文档的函数参数类型兼容性部分,其中提到:
当比较函数参数的类型时,如果源参数可以分配给目标参数,或者反之,赋值操作将成功。这种做法是不可靠的,因为调用者可能会最终得到一个接受更专门类型的函数,但使用较不专门类型的类型调用该函数。[...]
你可以通过编译器标志strictFunctionTypes让TypeScript在这种情况下引发错误。
我认为最后一句话“通过编译器标志strictFunctionTypes引发错误”需要明确指出这不适用于方法和构造函数。或者更好的做法是让它实际上与写的内容一致(并修复方法和构造函数,尽管我怀疑这可能需要一个单独的标志,如strictMethodTypes)。
虽然开发者被这个问题困扰时可以在报告bug之前查阅https://github.com/microsoft/TypeScript/wiki/FAQ#common-bugs-that-aren-t-bugs ,并意识到它的工作方式是预期的,但对于只阅读手册的开发者来说,在受到影响并开始报告bug之前了解这一点会更好。
另外,如果有一个严格性标志来应用到方法上,这将非常有用,因为通常在重构接口方法以接受更多类型时,不会意识到编译器会接受未更新的实现。我已经遇到过这种情况好几次。