这是如何工作的细节大多在76" rel="nofollow noreferrer">microsoft/TypeScript#"a"
76页中列出.像"a"
这样的字符串文字最初总是由编译器提供literal types,但根据上下文的不同,这些类型要么被认为是"widening",要么被认为是"non-widening".在某些情况下,加宽文本类型将自动加宽(因此"a"
将变为string
),而非加宽类型不会(因此"a"
将保持"a"
).
在以下方面:
const a = 'a' // 'a'
const c = [a] // string[]
为a
变量推断的类型是widening文字类型"a"
,因为初始值设定项"a"
出现在expression中.因此,对于[a]
推断的类型是string[]
,因为a
是加宽类型.
另一方面,
const a2:'a' = 'a' // 'a'
const c2 = [a2] // 'a'[]
为a2
推断的类型是non-widening文字类型"a"
,因为您将其本身作为annotated,并且"a"
出现在type而不是expression中.实际上,使用文本类型注释变量是获得非加宽类型而不是加宽类型的推荐方法.
最后,在
const a1 = 'a' as const // 'a'
const c1 = [a1] // 'a'[]
a1
类型是非加宽"a"
类型,因为const
assertions总是导致非加宽类型,如microsoft/TypeScript#29510中所述.
所以这就解释了为什么你会看到你所看到的.
关于为什么是useful的问题更难得到权威的回答,因为效用是主观的.你可以通读微软/TypeScrip#10676和microsoft/TypeScript#11126以及链接到它们的问题,以获得更多背景信息.
通常的问题是,有时人们希望像"a"
这样的值被字面上视为不变的值,而另一些人则希望它只被视为string
.这其中有一个权衡.除非人们明确地写出他们的意图,否则编译器必须使用有时可能是错误的启发式方法来确定这个意图是什么.
如果我写const a = "a"
,那么我知道它永远不会改变,所以不变和狭窄的"a"
类型是合适的.将a
视为string
并没有错,但它丢弃了信息.
如果我写为let b = "b"
,那么我可能会更改该值(否则我会使用const
),因此string
类型更合适.
如果我写成const c = [a]
,那么即使a
是"a"
类型,我也不清楚c
是否始终只包含"a"
类型的元素.那是..很奇怪,对吧?如果没有更多的上下文,很难想象为什么有人会想要一组字母"a"
.类型string[]
要常见得多,因此推断c
为string[]
是合理的.
如果您特意告诉编译器a
是"a"
类型的,那么启发式方法就会使用这一点.如果你有const a: "a" = "a"
,现在编译器有一些迹象表明你真的关心这个文字类型,现在const c = [a]
推断类型"a"[]
对应c
.我仍然认为这是一种奇怪的类型(我想你可以操作数组中"a"
的number),但这就是推断给你的.如果我不喜欢这个,我可以写const c: string[] = [a]
,并澄清我的意图.
这一行为是否有用,仍然是一个观点问题.我只能给出我自己的观点(它主要是有用的,偶尔也会出错,在这一点上我可以使用显式的注释),并指出记录在案的GitHub问题.