相似类型约束和条件类型的区别
Difference in between similar type constraint and conditional type
我自己编写了内置实用程序类型的实现 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
而不是例如never
?
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 | never
并且 BuiltInWithAny
的类型变为 R | any
- 如果 TS 无法解析
R
,则认为是 unknown
。所以,MyWithAny
的结果类型是unknown | never
即unkonown
,BuiltInWithAny
的结果类型是unknown | any
即any
你的例子可以简化成这样:
type WithNever = <T>(t: T) => T | never
type WithAny = <T>(t: T) => T | any
type NeverRetutn = ReturnType<WithNever>
type AnyRetutn = ReturnType<WithAny>
我们对 T | never
和 T | any
感兴趣。
如果 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
可分配给未知。
R | any
与 unknown | any
相同,并且因为任何类型都可以分配给 any
,所以您得到的只是 any
.
但是为什么你会收到类型的联合?
很明显,条件类型应该 return 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 | false
。 true | false
union 只是一个内置的 boolean
类型。
我不认为打字稿不够聪明。 TS只是告诉你 any
类型可以扩展构造函数类型,但同时它不能扩展。
我自己编写了内置实用程序类型的实现 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
而不是例如never
?
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 | never
并且BuiltInWithAny
的类型变为R | any
- 如果 TS 无法解析
R
,则认为是unknown
。所以,MyWithAny
的结果类型是unknown | never
即unkonown
,BuiltInWithAny
的结果类型是unknown | any
即any
你的例子可以简化成这样:
type WithNever = <T>(t: T) => T | never
type WithAny = <T>(t: T) => T | any
type NeverRetutn = ReturnType<WithNever>
type AnyRetutn = ReturnType<WithAny>
我们对 T | never
和 T | any
感兴趣。
如果 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
可分配给未知。
R | any
与 unknown | any
相同,并且因为任何类型都可以分配给 any
,所以您得到的只是 any
.
但是为什么你会收到类型的联合? 很明显,条件类型应该 return 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 | false
。 true | false
union 只是一个内置的 boolean
类型。
我不认为打字稿不够聪明。 TS只是告诉你 any
类型可以扩展构造函数类型,但同时它不能扩展。