如何理解类型 any、unknown、{} 之间以及它们与其他类型之间的关系? [英] How to undestand relations between types any, unknown, {} and between them and other types?
问题描述
试图理解类型之间的关系我有这个代码
Trying to understand relations between types I have this code
type CheckIfExtends<A, B> = A extends B ? true : false;
type T1 = CheckIfExtends<number, unknown>; //true
type T2 = CheckIfExtends<number, {}>; //true
type T3 = CheckIfExtends<number, any>; //true
type T4 = CheckIfExtends<() => void, unknown>; //true
type T5 = CheckIfExtends<() => void, {}>; //true
type T6 = CheckIfExtends<() => void, any>; //true
type T7 = CheckIfExtends<unknown, any>; //true
type T8 = CheckIfExtends<any, unknown>; //true
type T9 = CheckIfExtends<{}, unknown>; //true
type T10 = CheckIfExtends<{}, any>; //true
type T11 = CheckIfExtends<any, {}>; //boolean
type T12 = CheckIfExtends<unknown, {}>; //false
有人能解释一下吗?有什么区别?any extends {}
和 any
怎么可能不会同时扩展 {}
?如果 any extends unknown
和 unknown extends any
那么这是否意味着它们是强相等的?难道是 Typescript 在 JavaScript 的 null
和 undefinded
权益问题之上的新缺陷?
Could someone explain this? What difference? How is it possible that any extends {}
and any
does not extend {}
at the same time? If any extends unknown
and unknown extends any
then does it mean they are strongly equal? Is it a new flaw of Typescript on top of null
and undefinded
equity issue of JavaScript?
其实
type T = CheckIfExtends<any, number>; //boolean
推荐答案
本质上的区别在于:
any
类型 故意不合理,因为它可以分配给和来自任何其他类型(never
可能除外,这取决于您使用它的位置).不健全意味着类型的一些基本规则被破坏,例如传递性://en.wikipedia.org/wiki/Subtyping" rel="noreferrer">子类型.一般来说,如果A
可以赋值给B
,而B
可以赋值给C
,那么A
可分配给C
.但是any
打破了这一点.例如:string
可分配给any
,any
可分配给number
... 但字符串
不能分配给number
.这种特殊的不健全非常有用,因为它允许我们从根本上关闭"难以或不可能正确键入的代码部分中的类型检查.但是您需要非常小心地将any
视为一种类型;它更像是一种非类型".
the
any
type is deliberately unsound, in that it is assignable both to and from any other type (with the possible exception ofnever
, depending on where you're using it). Unsoundness means that some basic rules for types are broken, such as transitivity of subtyping. Generally, ifA
is assignable toB
, andB
is assignable toC
, thenA
is assignable toC
. Butany
breaks this. For example:string
is assignable toany
, andany
is assignable tonumber
... butstring
is not assignable tonumber
. This particular unsoundness is very useful, because it allows us to essentially "turn off" type checking in a part of code which is either hard or impossible to type correctly. But you need to be very careful thinking ofany
as a type; it's more of an "un-type".
空类型,{}
, 是一种可以在运行时被视为对象的类型(也就是说,您可以从中读取属性或方法而不会出现运行时错误),但它具有编译时没有已知属性.这并不意味着它没有属性;它只是意味着编译器不知道它们中的任何一个.这意味着只有 null
和 undefined
不能分配给 {}
(null.foo
或 undefined.foo
是运行时错误).甚至像 string
这样的原始类型也可以在运行时被视为具有属性和方法("".length
和 "".toUpperCase()
工作,甚至 "".foo
只返回 undefined
).当然,任何实际对象类型也将分配给 {}
.
the empty type, {}
, is a type that can be treated like an object at runtime (that is, something you can read properties or methods from without a runtime error), but it has no known properties at compile time. That doesn't mean it has no properties; it just means that the compiler doesn't know about any of them. This implies that only null
and undefined
are not assignable to {}
(null.foo
or undefined.foo
are runtime errors). Even primitive types like string
can be treated as having properties and methods at runtime ("".length
and "".toUpperCase()
work, and even "".foo
just returns undefined
). And of course any actual object type will also be assignale to {}
.
另一方面,{}
类型不能分配给很多类型.如果我尝试将 {}
类型的值分配给 {foo: string}
类型的变量,则会出现编译器错误,如 {}
不知道包含 foo
属性.您可以将 {}
分配给自身,或分配给更广泛的类型(如 unknown
),或分配给un-type"any
.
On the other hand, the {}
type is not assignable to very many types. If I have value of type {}
as try to assign it to a variable of type {foo: string}
, there will be a compiler error, as {}
is not known to contain a foo
property. You can assign {}
to itself, or to a wider type like unknown
, or to the "un-type" any
.
这使得 {}
非常几乎 成为顶级type,这是所有其他类型都可以分配的类型.它本质上是一个顶部类型,其中删除了 null
和 undefined
.
This makes {}
very nearly a top type, which is a type to which all other types are assignable. It's essentially a top type with null
and undefined
removed from it.
unknown
类型是在 TypeScript 3.0 中引入的,是 true 顶级类型;TypeScript 中的每个类型都可以分配给 unknown
.甚至 null
和 undefined
也可以分配给 unknown
.
the unknown
type was introduced in TypeScript 3.0 and is the true top type; every type in TypeScript is assignable to unknown
. Even null
and undefined
are assignable to unknown
.
另一方面,unknown
只能分配给它自己和un-type"any
.即使 {}
类型也不够宽,您无法将 unknown
分配给它.从概念上讲,您应该能够将 unknown
分配给联合类型 {} |空|未定义
,但这是故意未实施以保持unknown
作为真正的"顶级类型.
Again, on the other hand, unknown
is only assignable to itself and the "un-type" any
. Even the {}
type isn't wide enough for you to assign unknown
to it. Conceptually you should be able to assign unknown
to the union type {} | null | undefined
, but this is intentionally not implemented to keep unknown
as the "true" top type.
您的大部分 CheckIfExtends
结果都可以通过上述解释.例外是T11
:
Most of your CheckIfExtends<A, B>
results can be explained by the above. The exception is T11
:
type T11 = CheckIfExtends<any, {}>; //boolean
您的 CheckIfExtends
类型定义是 分布式条件类型,当 A
是联合类型时,它会做一些有趣的事情,因为它允许条件的两个分支如果联合的部分满足两个分支,则采用.当 A
是 any
时,它也做同样的分布,除非 B
是 any
或 unknown
(所以 T8
表现正常).microsoft/TypeScript#27418 对此有一些讨论.无论如何,T11
需要两个分支,你就会得到 true |false
是 boolean
.(来自 microsoft/TypeScript#27418,A
位置的 unknown
不分布,所以 T7
和 T12
表现通常也是如此).
Your CheckIfExtends<A, B>
type definition is a distributive conditional type, which does some interesting things when A
is a union type, in that it allows both branches of the conditional to be taken if the pieces of the union satisfy both branches. It also does the same distribution when A
is any
, except when B
is any
or unknown
(so T8
behaves normaly). There's some discussion of this in microsoft/TypeScript#27418. Anyway, T11
takes both branches and you get true | false
which is boolean
. (From microsoft/TypeScript#27418, unknown
in the A
position does not distribute, so T7
and T12
behave normally as well).
好的,希望有帮助;祝你好运!
Okay, hope that helps; good luck!
这篇关于如何理解类型 any、unknown、{} 之间以及它们与其他类型之间的关系?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!