TypeScript 中的“as const”是什么意思,它的用例是什么? 没有 as const 断言

问题描述

我对 as const 演员表感到困惑。我查了一些文档和视频,但没有完全理解。

我关心的是下面代码中的 as const 是什么意思,使用它有什么好处?

const args = [8,5] as const;
const angle = Math.atan2(...args);
console.log(angle);

解决方法

这称为 const assertionconst 断言告诉编译器为表达式推断最窄*最具体 类型。如果您不使用它,编译器将使用其默认的类型推断行为,这可能会导致更宽更通用的类型。

请注意,它被称为“断言”而不是“强制转换”。在 TypeScript 中通常要避免使用术语“cast”;当人们说“cast”时,他们通常暗示某种可以在运行时观察到的效果,但是 TypeScript 的类型系统,包括类型断言和 const 断言,完全 erased 来自发出的 JavaScript。因此,使用 as const 的程序和不使用 as const 的程序在运行时完全没有区别。


不过,在编译时,有一个明显的区别。让我们看看当您在上面的示例中省略 const args = [8,5]; // const args: number[] const angle = Math.atan2(...args); // error! Expected 2 arguments,but got 0 or more. console.log(angle); 时会发生什么:

const args = [8,5];

编译器看到 number[] 并推断出 number 的类型。这是一个由零个或多个 args.push(17) 类型元素组成的可变数组。编译器不知道有多少哪些元素。这样的推断通常是合理的;通常,数组内容旨在以某种方式进行修改。如果有人想写 args[0]++number[],他们会对 Math.atan2(...args) 的类型感到满意。

不幸的是,下一行 Math.atan2() 导致错误。 args 函数正好需要两个数字参数。但是编译器只知道 Math.atan2() 是一个数字数组。它完全忘记了有两个元素,因此编译器会抱怨您在调用 as const 时只需要两个,而参数是“0 个或多个”。


将其与带有 const args = [8,5] as const; // const args: readonly [8,5] const angle = Math.atan2(...args); // okay console.log(angle); 的代码进行比较:

args

现在编译器推断 readonly [8,5] 的类型为 8...一个 readonly tuple,其值正好是该顺序中的数字 5args.length .具体来说,编译器知道 2 正好是 Math.atan2()

这足以让带有 Math.atan2(...args) 的下一行工作。编译器知道 Math.atan2(8,5)1.0121970114513341 相同,这是一个有效的调用。


再说一遍:在运行时,没有任何区别。两个版本都将 const 记录到控制台。但是 readonly 断言与静态类型系统的其余部分一样,并不意味着在运行时产生影响。相反,它们让编译器更多地了解代码的意图,并且可以更准确地分辨正确代码和错误之间的区别。

Playground link to code


* 对于数组和元组类型,这不是严格的; readonly 数组或元组在技术上比可变版本更宽。可变数组被认为是 push() 数组的子类型;前者不知道有像 -- Setting output GPIO pins multip = { sc0 = 0,sc1 = 3,sc2 = 4 } for k3,v3 in pairs(multip) do gpio.mode(v3,gpio.OUTPUT) end -- Assigning ADC channels HIHs = { hum1 = { sc0 = gpio.HIGH,sc1 = gpio.LOW,sc2 = gpio.HIGH },hum2 = { sc0 = gpio.LOW,sc1 = gpio.HIGH,hum3 = { sc0 = gpio.HIGH,sc2 = gpio.HIGH } } -- Sequentially access each channel and read value for g,t in pairs(HIHs) do print("---------- Setting Humidity sensor " .. g .. " ----------") for k4,v4 in pairs(multip) do print("Writing pin " .. k4 .. " to " .. tostring(t[k4])) gpio.write(v4,t[k4]) end print("ADC Value: "..adc.read(0)) end 这样的变异方法,而后者有。

,

如果您要编写 const args = [8,5],则没有什么可以阻止您同时编写 args[0] = 23args.push(30) 或其他任何内容来修改该数组。您所做的只是告诉 TS/JS 名为 args 的变量指向该特定数组,因此您无法更改它所引用的内容(例如,您不能执行 args = "something else")。您可以修改数组,但不能更改其变量指向的内容。

另一方面,现在将 as const 添加到声明中确实使其成为常量。整个事情是只读的,所以你根本不能修改数组。


澄清,正如评论中所指出的:

“真的让它保持不变”可能意味着当没有运行时效果时会有一些运行时效果。在运行时, args.push(30) 仍然会修改数组。 const 所做的就是让它在 TypeScript 编译器看到你这样做时会抱怨。 – jcalz

as const 只影响编译器,它的只读效果有一个例外(见注释)。但总的来说,这仍然是 constas const 之间的主要使用区别。一个用于使引用不可变,另一个用于使被引用的内容不可变。

,

这是一个 const 断言。 Here is a handy post on themhere is the documentation

当我们用 const 断言构造新的文字表达式时,我们可以向语言发出信号

  • 该表达式中的任何文字类型都不应加宽(例如,不要从“hello”变为字符串)
  • 对象字面量获得只读属性
  • 数组文字变成只读元组

对于 const args = [8,5] as const;,第三个项目符号适用,ts 会理解它的意思:

// 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];

没有断言:

// Type: number[]
const args = [8,5];

// Ok
args[0];
args[1];

// Also Ok.
args[2];
,

简而言之,as const 可让您创建完整的 readonly 对象

在您的代码中,as const 表示数组位置值为 readonly,它们被称为 const assertions,以下示例考虑正在实现的断言:

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]'"

我在回答开头所做的“完全只读”声明有一些例外,您可以查看它们here但总的来说,好处是将 readonly 添加到其所有对象属性中。

没有 as const 断言

args 仍然是一个常量,但是你仍然可以修改它的内部值(非常没用),这是有效的:

const args = [8,5];
args[0] = 3;  // works
args.push(3); // works

const 只会阻止您直接为变量赋值:

args = 7; // throws "Assignment to constant variable" because of the 'const' declaration

我不想谈论他们在这里的内部工作方式。有关更多信息,请查看其他相关问题/答案:

  1. How do I declare a read-only array tuple in TypeScript?
  2. Any difference between type assertions and the newer as operator in TypeScript?

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...