const args = [8, 5] as const;
args[0] = 3; // throws "Cannot assign to '0' because it is a read-only
args.push(3); // throws "Property 'push' does not exist on type 'readonly [8, 5]'"
在最后一个抛出的错误中,您可以看到args = [8, 5] as const被解释为args: readonly [8, 5],这是因为第一个声明等效于一个只读元组。
const args = [8, 5];
// Without `as const` assert; `args` stills a constant, but you can modify its attributes
args[0] = 3; // -- WORKS
args.push(3); // -- WORKS
// You are only prevented from assigning values directly to your variable
args = 7; // -- THROWS ERROR
对于const args = [8, 5] as const;,第三个项目符号适用,tsc会理解它的意思:
// Type: readonly [8, 5]
const args = [8, 5] as const;
// Ok
args[0];
args[1];
// Error: Tuple type 'readonly [8, 5]' of length '2' has no element at index '2'.
args[2];
没有Assert:
// Type: number[]
const args = [8, 5];
// Ok
args[0];
args[1];
// Also Ok.
args[2];
5条答案
按热度按时间9njqaruj1#
这称为
const
Assert。const
Assert告诉编译器为表达式推断 * 最窄**或 * 最具体 * 的类型。如果不设置它,编译器将使用其默认类型推断行为,这可能会导致 * 更宽 * 或 * 更一般 * 的类型。请注意,它被称为"Assert"而不是"强制转换"。在TypeScript中通常要避免使用术语"强制转换";当人们说"cast"的时候,他们通常暗示着某种可以在运行时观察到的效果,但是TypeScript的类型系统,包括类型Assert和
const
Assert,从发出的JavaScript中被完全删除了,所以在运行时,使用as const
的程序和不使用as const
的程序之间绝对没有什么区别。但是在编译时,有一个明显的区别,让我们看看在上面的例子中省略
as const
会发生什么:编译器看到
const args = [8, 5];
并推断number[]
的类型,这是一个由零个或多个number
类型元素组成的可变数组,编译器不知道有多少或哪些元素,这样的推断通常是合理的;数组的内容通常是可以被修改的,如果有人想写args.push(17)
或args[0]++
,他们会很乐意使用number[]
类型。不幸的是,下一行
Math.atan2(...args)
产生了一个错误,Math.atan2()
函数需要两个数值参数,但是编译器只知道args
是一个数字数组,它完全忘记了有两个元素,所以编译器抱怨你用"0或更多"参数调用Math.atan2()
,而它需要两个参数。将其与
as const
的代码进行比较:现在编译器推断
args
的类型为readonly [8, 5]
...readonly
元组,其值恰好为数字8
和5
,具体来说,编译器已知args.length
恰好为2
。这足以让
Math.atan2()
的下一行工作,编译器知道Math.atan2(...args)
与Math.atan2(8, 5)
相同,这是一个有效的调用。同样,在运行时,没有任何区别,两个版本都将
1.0121970114513341
记录到控制台,但是const
Assert,像静态类型系统的其他部分一样,并不意味着在运行时有效果,相反,它们让编译器更多地了解代码的 * 意图 *,并且可以更准确地区分正确代码和bug。Playground代码链接
readonly
数组或元组在技术上比可变版本"更宽"。可变数组被认为是readonly
数组的子类型;不知道前者具有如push()
的突变方法,而后者具有。mrfwxfqh2#
简而言之,它可以让你创建完全只读的对象,这就是
const assertion
,在你的代码中as const
意味着数组位置值是readonly
,下面是一个它是如何工作的例子:在最后一个抛出的错误中,您可以看到
args = [8, 5] as const
被解释为args: readonly [8, 5]
,这是因为第一个声明等效于一个只读元组。元组有很多用例,例如:spread parameters, destructive values, etc.。一般的好处是
readonly
行为被添加到其所有对象属性中:有一些Assert是“完全只读”的例外,你可以在这里查看。更多细节,这里有一个帮助我理解constAssert的其他相关问题/答案的列表:
1.如何在TypeScript中声明只读数组元组?
as
operator in TypeScript?icomxhvb3#
如果你要写
const args = [8, 5]
,没有什么能阻止你写args[0] = 23
或args.push(30)
或其他任何东西来修改那个数组,你所做的就是告诉TS/JS变量args
指向那个特定的数组,所以你不能改变它引用的东西(例如,你不能做args = "something else"
)。你可以修改数组,但不能改变它的变量指向什么。另一方面,现在将
as const
添加到声明中 * 真的 * 会使它成为常量,整个声明都是只读的,所以根本不能修改数组。澄清一下,正如评论中所指出的:
“really makes it constant”可能意味着在没有运行时效果的情况下存在一些运行时效果。在运行时,args.push(30)仍然会修改数组。const所做的一切就是使它成为一个常量,以便TypeScript编译器在看到你这样做时会发出抱怨。- jcalz
as const
只影响编译器,它的只读效果有一个例外(见注解),但总的来说,这仍然是const
和as const
在使用上的主要区别,一个用来使 * 一个引用 * 不可变,另一个用来使 * 被引用的内容 * 不可变。wpcxdonn4#
这是一个
const
Assert,Here is a handy post on them,这里是文档。当我们用constAssert构造新的文本表达式时,我们可以向语言发出信号
对于
const args = [8, 5] as const;
,第三个项目符号适用,tsc会理解它的意思:没有Assert:
ygya80vv5#
当
as const
应用于对象或数组时,它使它们不可变(即使它们只读)。对于其他文本,它防止类型扩展。其他优势很少**:**