Skip to content

TypeScript - 变量

变量是编程中的基本元素,用于存储和管理数据。它们充当命名容器,用于存放程序可以操作的值。在 TypeScript 中,与现代 JavaScript (ES6+) 一样,变量主要使用 let 和 const 关键字声明。

TypeScript 变量名必须遵循 JavaScript 的命名规则:

  • 名称可以包含字母、数字、下划线 (_) 和美元符号 ($)。
  • 名称必须以字母、下划线 (_) 或美元符号 ($) 开头。不能以数字开头。
  • 名称区分大小写(myVar 和 myvar 是不同的)。
  • 保留关键字(如 let, const, class, function 等)不能用作变量名。
  • 名称不能包含空格。

变量必须在使用前声明。

现代 TypeScript(和 JavaScript)相比旧的 var 关键字更倾向于使用 let 和 const,因为它们具有更好的作用域规则(块级作用域)和行为。

  • const:用于声明初始化后不会被重新赋值的变量。它创建的是一个不可变的绑定,而不是一个不可变的值(例如,你可以修改 const 对象的属性,但不能将一个新对象赋值给该变量)。默认情况下优先使用 const。
  • let:用于声明稍后可能被重新赋值的变量。let 允许你改变变量所持有的值。

let 和 const 都引入了块级作用域。使用 let 或 const 声明的变量仅在其定义所在的块(由 {} 包围)内可访问。

TypeScript 允许(并鼓励)使用冒号 (:) 后跟类型名的方式,为变量添加显式的类型注解。

let age: number = 30;
const pi: number = 3.14159;
let username: string = "Alice";
const isActive: boolean = true;
let anything: any; // Avoid 'any' if possible
let unknownValue: unknown; // Safer alternative to 'any'
// Reassigning 'let' variable is allowed
age = 31;
username = 'Bob';
// Reassigning 'const' variable is NOT allowed
// pi = 3.14; // Error: Cannot assign to 'pi' because it is a constant.
// isActive = false; // Error

如果你初始化变量时赋予了一个值,但没有提供显式的类型注解,TypeScript 通常会根据初始值推断出其类型。这可以使代码更简洁。

let inferredAge = 30; // TypeScript infers 'number'
const inferredUsername = "Alice"; // TypeScript infers 'string'
// inferredAge = "thirty"; // Error: Type 'string' is not assignable to type 'number'.

虽然类型推断很强大,但显式地注解类型(特别是函数参数/返回类型和复杂的对象结构)可以提高代码清晰度,并有助于防止细微的 bug。

语法描述
const name: string = "mary";声明一个带有显式类型和初始值的常量变量。类型不能改变,值不能重新赋值。
let score: number;声明一个带有显式类型但没有初始值的变量。在赋值之前其值为 undefined。之后可以重新赋值为指定类型 (number) 的值。
const city = "London";声明一个带有初始值的常量变量。TypeScript 会推断出其类型 (string)。值不能重新赋值。
let count;声明一个既没有类型也没有初始值的变量。TypeScript 会推断其类型为 any。其值为 undefined。可以重新赋值为任何类型的值(通常不推荐)。
const studentName: string = "John Doe";
let score1: number = 85;
let score2: number = 92.5;
let totalScore = score1 + score2; // Inferred type: number
console.log(`Name: ${studentName}`);
console.log(`First score: ${score1}`);
console.log(`Second score: ${score2}`);
console.log(`Total score: ${totalScore}`);
score1 = 88; // Allowed because score1 is declared with 'let'
console.log(`Updated first score: ${score1}`);
// studentName = "Jane Doe"; // Error: Cannot assign to 'studentName' because it is a constant.

有时,你可能比 TypeScript 拥有关于变量类型的更具体信息(特别是在处理 any 或 unknown 类型的值时,或与外部 JavaScript 交互时)。类型断言允许你告诉编译器将变量视为特定类型。它纯粹是一种编译时结构,没有运行时效应;它不会在运行时执行任何转换或检查。

有两种语法:

  • 尖括号语法 (Angle-bracket syntax): <Type>value
  • as 语法 (as syntax): value as Type(推荐使用,特别是在 JSX/TSX 文件中,尖括号与 HTML/XML 语法冲突)。

谨慎使用类型断言,仅在你确定类型时使用,因为它们会绕过标准的类型检查。

let someValue: unknown = "this is a string";
// We know it's a string, but TypeScript only knows it's 'unknown'.
// We need to assert the type to use string methods.
// Using 'as' syntax (preferred):
let strLength: number = (someValue as string).length;
console.log(`String length (using 'as'): ${strLength}`);
// Using angle-bracket syntax:
let strLength2: number = (<string>someValue).length;
console.log(`String length (using '<>'): ${strLength2}`);
// Incorrect assertion can lead to runtime errors:
let problematicValue: any = 123;
// const len = (problematicValue as string).length; // Compiles, but will likely cause a runtime error!
// console.log(len); // TypeError: problematicValue.length is not a function

作用域决定了变量在代码中的可访问性。TypeScript 利用 let 和 const,主要使用以下几种作用域:

  • 全局作用域 (Global Scope): 在任何函数或块外部声明的变量。在模块中,顶层变量的作用域限定在模块内,除非显式地附加到全局对象(例如,浏览器中的 window,不推荐)上,否则不是真正的全局变量。
  • 模块作用域 (Module Scope): 在模块文件(包含 import 或 export 的 .ts 文件)的顶层声明的变量只能在该模块内访问,除非被导出。
  • 函数作用域 (Function Scope): 在函数内部声明的变量通常只能在该函数内部访问(也适用于 var)。
  • 块级作用域 (Block Scope): 使用 let 或 const 在块(例如 if, for, {})内部声明的变量只能在该特定块内部访问。
// Module Scope (if this is in a module file)
const moduleVar: string = "I am module-scoped";
function testScope(condition: boolean): void {
// Function Scope
const functionVar: string = "I am function-scoped";
console.log(moduleVar); // Accessible
if (condition) {
// Block Scope
let blockVar: string = "I am block-scoped";
const anotherBlockVar: number = 10;
console.log(functionVar); // Accessible
console.log(blockVar); // Accessible
}
// console.log(blockVar); // Error: Cannot find name 'blockVar'. (Outside its block)
}
testScope(true);
// console.log(functionVar); // Error: Cannot find name 'functionVar'. (Outside its function)

理解 let 和 const 的块级作用域对于防止与旧 var 关键字的函数作用域和变量提升 (hoisting) 行为相关的常见错误至关重要。