typescript - 为什么没有参数扩展未知[](数组) 在 ts 严格模式下
问题描述
标题几乎说明了一切。我有这个代码:
type testNoArgsF = () => number;
type testArgsF = (arg1: boolean, arg2: string) => number;
type unknownArgsF = (...args: unknown[]) => number;
type anyArgsF = (...args: any[]) => number;
type testII = testArgsF extends anyArgsF ? true : false; // true
type testIII = Parameters<testArgsF> extends Parameters<unknownArgsF>
? true
: false; // true
// unexpected:
type testIV = testArgsF extends unknownArgsF ? true : false; // false <- why?
// even though:
type testV = testNoArgsF extends unknownArgsF ? true : false; // true
它是用打字稿(3.8 版)编写的,我启用了严格模式。出乎意料的结果是测试函数没有扩展带有扩展参数的函数类型unknown[]
,但是如果您只是检查它们确实扩展的参数unknown[]
。由于返回类型始终是数字,我不明白还有什么不同的地方可以伪造extends
语句。
其他注意事项:
- 仅当您的测试函数有 0 个参数时,扩展语句才为真。
- 如果您关闭严格模式,则不会出现此行为。
解决方案
--strictFunctionTypes
启用编译器选项后,会以逆变方式检查函数类型参数。“逆变”是指函数的子类型关系与函数参数的子类型关系的变化方向相反。因此,如果A extends B
,则(x: B)=>void extends (x: A)=>void
反之亦然。
由于 TypeScript 中的“可替代性”(也称为行为子类型化)的性质,这是一个类型安全问题。如果A extends B
为真,您应该能够将 anA
用作B
. 如果你不能,那就A extends B
不是真的。
如果您关闭,--strict
那么编译器会使用 TS-2.6 之前的行为来检查函数参数bivariantly,这是不安全的,但出于生产力的原因是允许的。这可能是题外话,但您可以在 TypeScript 常见问题解答条目“为什么函数参数是双变量的?”中阅读更多相关信息。
无论如何,如果你需要一个接受任何数字unknown
参数的函数类型,你不能安全地使用一个只有特定子类型的函数unknown
。观察:
const t: testArgsF = (b, s) => (b ? s.trim() : s).length
const u: unknownArgsF = t; // error!
u(1, 2, 3); // explosion at runtime! s.trim is not a function
如果testArgsF extends unknownArgsF
为真,那么您将能够在没有错误的情况下分配t
给上面,当愉快地接受非第二个参数 u
时立即导致运行时错误。u
string
您可以看到子类型/实现函数类型的唯一安全方法是子类型/实现接受与超类型/调用签名预期的参数相同或更宽的参数。这就是为什么--strictFunctionTypes
被引入该语言的原因。
如果您更改unknown
为any
(使用anyArgsF
而不是unknownArgsF
),则编译器不会抱怨,因为在 TypeScriptany
中故意不正确。该类型any
被认为可以分配给其他所有类型,也可以分配给其他类型;这是不安全的,因为例如string extends any
和any extends number
都是真的而string extends number
都是假的。因此,上述替代原则在any
涉及时不强制执行。将值注释为any
类型相当于放松或关闭对该值的类型检查。这并不能使您免于运行时错误;它只是消除了编译器的错误:
const a: anyArgsF = t; // okay, type checking with any is disabled/loosened
a(1, 2, 3); // same explosion at runtime!
在 wheretestNoArgsF extends unknownArgsF
为真的情况下,这也是可替代性的结果。您可以使用不带参数的函数,就好像它几乎是任何函数类型一样,因为它(通常)最终会忽略传递给它的任何参数:
const n: testNoArgsF = () => 1;
const u2: unknownArgsF = n; // okay
u2(1, 2, 3); // okay at runtime, since `n` ignores its arguments
这在 TypeScript 常见问题解答条目“为什么具有较少参数的函数可分配给采用更多参数的函数?”中进行了解释。.
好的,希望有帮助;祝你好运!
推荐阅读
- solidity - 我收到一个错误,一个声明错误,但它指向我不明白的引号中的内容
- cypress - cypress 测试套件是否有办法在其输出中取消屏蔽敏感信息以进行调试?
- powerbi - 根据用户动态更改 power bi 嵌入式报表
- android - 如何在 Jetpack Compose Text 中居中(水平和垂直)文本
- python - 如何根据另一列的值计数从 Pandas Dataframe 中采样数据
- python - PyGame 在第二个屏幕上正常,但在笔记本电脑屏幕上显示黑屏
- python - 在数据框列中分离出逗号分隔的项目并获取单独的计数
- python - 尝试从网站实时抓取文章时,我总是遇到延迟
- javascript - 如何通过JS为html元素创建升序号?
- amazon-web-services - 安全组 aws 特定 ip http/https 阻止一切