我已经编写了自己的内置实用程序类型 InstanceType
的实现:
type MyInstanceType<C extends abstract new (...args: any) => any>
= C extends abstract new (...args: any) => infer R ? R : never
它与实际实现方式非常接近:
type BuiltInInstanceType<C extends abstract new (...args: any) => any>
= C extends abstract new (...args: any) => infer R ? R : any
唯一的区别是我最后说的是 never
而实际的实现是 any
这导致它对待any
的方式不同:
type MyWithAny = MyInstanceType<any> // unknown
type BuiltInWithAny = BuiltInInstanceType<any> // any
我假设这意味着它以某种方式到达了条件类型的虚假分支
所以问题是,这怎么可能?考虑到条件类型与类型约束相同,所以任何对条件类型为假的东西对于类型约束也应该是假的,因此应该导致类型约束失败错误
第二个问题,为什么 MyWithAny
恰好是 unknown
而不是例如从不
?
UPD:根据答案和讨论,这是它的评估方式(接受的答案中有更多详细信息):
- 在评估
MyWithAny
和BuiltInWithAny
时,使用any
作为通用函数的参数已完全禁用类型约束。所以MyInstanceType
已经被评估为它是
type MyInstanceType<C> = C extends abstract new (...args: any) => infer R ? R : never
和 BuiltInInstanceType
已按原样计算
type BuiltInInstanceType<C> = C extends abstract new (...args: any) => infer R ? R : any
这使得伪分支成为可能
- 如果 TS 无法评估条件类型的分支,它会将其评估为两个分支的联合类型。因此,因为
any
包含可能满足或不满足条件类型的实例,所以MyWithAny
的类型变成了R |从不
并且BuiltInWithAny
的类型正在变为R |任何
- 如果 TS 无法解析
R
,它会认为是unknown
。所以,MyWithAny
的结果类型是unknown | never
即unkonown
,BuiltInWithAny
的结果类型为unknown |任何
即任何
最佳答案
你的例子可以简化成这样:
type WithNever = <T>(t: T) => T | never
type WithAny = <T>(t: T) => T | any
type NeverRetutn = ReturnType<WithNever>
type AnyRetutn = ReturnType<WithAny>
我们对 T | 感兴趣从不
和T |任何
。
如果 TypeScript 无法推断 T
的类型,TS 将分配 unknown
类型。
看例子:
type ReturnUnknown = ReturnType< <T>(t: T) => T> // unknown
什么是never
? ( docs )
The never type is a subtype of, and assignable to, every type
事实上,您应该将never
视为空联合。
type Check = 1 | never // 1
type Check2 = unknown | never // unknown
type Check3 = any | never // any
您可能已经注意到,never
被分配给每种类型。
让我们回到您的问题。事实上,您正在接收类型的联合。
type MyWithAny = MyInstanceType<any> // R | never
type BuiltInWithAny = BuiltInInstanceType<any> // R | any
我希望,现在很清楚,R | never
将被解析为 unknown
,因为 R
是未知的,而 never
可分配给 unknown。
R | any
与 unknown | 相同any
,因为任何类型都可以分配给 any
,所以您得到的只是 any
。
但是为什么你会收到类型的联合? 很明显,条件类型应该返回 true 或 false 分支,但不能同时返回。这不是它在 TS 中的工作方式。
因为您提供了 any
作为参数,所以每个分支都会被应用。我认为这是预料之中的,因为我没有足够的论据说应该只应用 true 分支,或者只应用 false 分支。
Considering that conditional type is the same as type constraint and so anything that is falsy to the conditional type should also be falsy to type constraint and so should result in a type constraint failed error
因为 any
类型实际上是任何类型(每种类型),为什么您认为应该应用 false
分支?请记住,您使用的是类型,而不是值。
What is confusing to me about falsy branch is that how I understand it, it should always be evacuated to never, no matter what we put there
它不能总是被评估为假分支。这种假设是不正确的。
考虑下一个例子:
type CheckAny = any extends abstract new (...args: any) => any ? true : false
以上条件的计算结果为 true |错误
。和 true | false
union 只是一个内置的 boolean
类型。
我不认为 typescript 不够聪明。 TS 只是告诉你,任何
类型都可以扩展构造函数类型,但同时它不能扩展。
关于typescript - 相似类型约束和条件类型的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68435374/