好的,还有一件事让我感到困惑:

通常我们可以跳过类型注释,因为我们知道类型脚本会为我们推断类型.

但事实证明,在某些情况下,使用或不使用类型注释确实有很大的不同:

const a = 'a' // 'a'
//    ^?
const c = [a] // string[]
//    ^?

const a1 = 'a' as const // 'a'
//    ^?
const c1 = [a1] // 'a'[]
//    ^?

const a2:'a' = 'a' // 'a'
//    ^?
const c2 = [a2] // 'a'[]
//    ^?

playground

所以现在我知道它是怎么运作的了.

但我的问题是:为什么在Case c中,它被扩大到string[],它有什么用处?

注意:这与数组或元组的工作方式无关,也与常量和类型批注的工作方式无关.问题是,为什么c不跟在c1c2之后,或者c1c2不跟在c后面,为什么不是所有东西都是元组,或者所有东西都是数组,为什么c一定是不同的?

c也扩大到string,这并不可取,因为扩大意味着不安全,保持c扩大的意义是什么?

推荐答案

这是如何工作的细节大多在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[]要常见得多,因此推断cstring[]是合理的.

如果您特意告诉编译器a"a"类型的,那么启发式方法就会使用这一点.如果你有const a: "a" = "a",现在编译器有一些迹象表明你真的关心这个文字类型,现在const c = [a]推断类型"a"[]对应c.我仍然认为这是一种奇怪的类型(我想你可以操作数组中"a"number),但这就是推断给你的.如果我不喜欢这个,我可以写const c: string[] = [a],并澄清我的意图.

这一行为是否有用,仍然是一个观点问题.我只能给出我自己的观点(它主要是有用的,偶尔也会出错,在这一点上我可以使用显式的注释),并指出记录在案的GitHub问题.

Typescript相关问答推荐

如何为ViewContainerRef加载的Angular组件实现CanDeactivate保护?

如何为父类构造函数中的修饰属性赋值?

有没有办法解决相互影响的路由之间的合并?

如何表示多层深度的泛型类型数组?

如何在TypeScrip中正确键入元素和事件目标?

在类型脚本中的泛型类上扩展的可选参数

通过按键数组拾取对象的关键点

有没有可能产生输出T,它在视觉上省略了T中的一些键?

刷新页面时,TypeScrip Redux丢失状态

RXJS将对键盘/鼠标点击组合做出react

为什么Typescript只在调用方提供显式泛型类型参数时推断此函数的返回类型?

判断映射类型内的键值的条件类型

避免混淆两种不同的ID类型

如何从一个泛型类型推断多个类型

TS2739将接口类型变量赋值给具体变量

如何解决&Quot;类型不可分配给TypeScrip IF语句中的类型&Quot;?

具有匹配功能的TS通用事件处理程序

换行TypeScript';s具有泛型类型的推断数据类型

带有 Select 器和映射器的Typescript 泛型

通用可选函数参数返回类型