【Typescript】一句赋值语句,为什么有两个 const?
看到下面这个语句,你会不会有疑问:是不是 const 重复了?
const supported = ["en", "es", "zh-cn", "zh-tw"] as const;
这两个 const 关键字的作用是不同的,因此它们不重复,而是协同工作,共同达到一个更严格的类型定义和运行时行为。
让我们来详细解释:
-
第一个
const:const supported = ...- 作用对象: 这个
const是 JavaScript 语言本身的关键字,作用于变量声明。 - 作用: 它声明了一个常量变量。这意味着你不能重新赋值
supported这个变量。const supported = ["en", "es"] as const; supported = ["fr"]; // ❌ 错误:不能重新赋值 'supported' - 运行时效果: 在 JavaScript 运行时层面,这个变量不能被重新绑定到其他值。
- 作用对象: 这个
-
第二个
const:as const- 作用对象: 这个
as const是 TypeScript 独有的类型断言(type assertion)。它作用于值本身(这里是一个数组字面量["en", "es", "zh-cn", "zh-tw"])。 - 作用:
- 字面量类型推断 (Literal Type Inference): 它告诉 TypeScript,把这个数组中的每个元素都推断为最窄的字面量类型,而不是更宽泛的类型。
- 没有
as const,"en"会被推断为string类型。 - 有
as const,"en"会被推断为"en"字面量类型。
- 没有
- 只读性 (Readonly): 它会将整个数组(或对象)推断为深度只读(deeply readonly)。这意味着你不能修改数组的元素。
- 数组会变成
readonly [...]元组类型。 - 如果它是一个对象,所有属性也会变成
readonly。
- 数组会变成
- 字面量类型推断 (Literal Type Inference): 它告诉 TypeScript,把这个数组中的每个元素都推断为最窄的字面量类型,而不是更宽泛的类型。
- 类型层面效果:
- 没有
as const:supported的类型会被推断为string[](一个字符串数组)。const supportedWithoutConst = ["en", "es"]; // Type: string[] supportedWithoutConst[0] = "fr"; // ✅ 允许:因为它是 string[],元素可修改 - 有
as const:supported的类型会被推断为readonly ["en", "es", "zh-cn", "zh-tw"](一个只读的,包含特定字面量字符串的元组)。const supportedWithConst = ["en", "es"] as const; // Type: readonly ["en", "es"] supportedWithConst[0] = "fr"; // ❌ 错误:因为它是只读元组,元素不可修改
- 没有
- 运行时效果:
as const在编译成 JavaScript 后会被完全移除,它在运行时没有任何效果。它纯粹是 TypeScript 在编译阶段提供类型安全和更精确类型推断的机制。
- 作用对象: 这个
总结
const(第一个): 保证变量supported本身不能被重新赋值。这是一个运行时的概念。as const(第二个): 保证supported所指向的值(数组)的内容不能被修改,并且其元素的类型被精确地推断为字面量类型。这是一个编译时(TypeScript)的概念。
它们一起使用,可以确保 supported 变量始终指向同一个数组,并且该数组的元素内容在整个程序生命周期中都不会被修改,同时为 TypeScript 提供最精确的类型信息。
最常见的用途是,当你需要从这个数组中派生出一个联合类型时:
const supported = ["en", "es", "zh-cn", "zh-tw"] as const;// 使用 typeof supported[number] 可以得到一个包含所有支持语言的联合类型
type SupportedLanguage = typeof supported[number];
// 结果:type SupportedLanguage = "en" | "es" | "zh-cn" | "zh-tw"function setLanguage(lang: SupportedLanguage) {console.log(`Setting language to: ${lang}`);
}setLanguage("en"); // ✅
setLanguage("fr"); // ❌ 错误:'fr' 类型不可赋值给 'SupportedLanguage' 类型。
supported[0] = "de"; // ❌ 错误:类型推断为 readonly,不可修改元素
如果没有 as const,typeof supported[number] 只会得到 string 类型,就达不到这种类型安全的控制效果。
