Skip to content

TypeScript - Variables

Variables are fundamental elements in programming used to store and manage data. They act as named containers for values that your program can manipulate. In TypeScript, as in modern JavaScript (ES6+), variables are primarily declared using the let and const keywords.

TypeScript variable names must follow JavaScript naming rules:

  • Names can contain letters, digits, underscores (_), and dollar signs ($).
  • Names must begin with a letter, underscore (_), or dollar sign ($). They cannot start with a digit.
  • Names are case-sensitive (myVar and myvar are different).
  • Reserved keywords (like let, const, class, function, etc.) cannot be used as variable names.
  • Names cannot contain spaces.

Variables must be declared before they are used.

Modern TypeScript (and JavaScript) heavily favors let and const over the older var keyword due to their improved scoping rules (block scope) and behavior.

  • const: Used for variables whose value will not be reassigned after initialization. It creates an immutable binding, not an immutable value (e.g., you can modify properties of a const object, but not assign a new object to the variable). Prefer const by default.
  • let: Used for variables whose value may be reassigned later. let allows you to change the value held by the variable.

Both let and const introduce block scoping. A variable declared with let or const is only accessible within the block (enclosed by {}) where it is defined.

TypeScript allows (and encourages) explicit type annotations for variables using a colon (:) followed by the type name after the variable name.

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

If you initialize a variable with a value but don’t provide an explicit type annotation, TypeScript will often infer the type based on the initial value. This can make code more concise.

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

While type inference is powerful, explicitly annotating types (especially for function parameters/return types and complex object structures) improves code clarity and helps prevent subtle bugs.

SyntaxDescription
const name: string = "mary";Declare a constant variable with an explicit type and initial value. Type cannot change, value cannot be reassigned.
let score: number;Declare a variable with an explicit type but no initial value. Its value is undefined until assigned. Can be reassigned later with values of the specified type (number).
const city = "London";Declare a constant variable with an initial value. TypeScript infers the type (string). Value cannot be reassigned.
let count;Declare a variable without type or initial value. TypeScript infers the type as any. Its value is undefined. Can be reassigned with any type (generally discouraged).
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.

Sometimes, you might have more specific information about a variable’s type than TypeScript does (especially when dealing with values of type any or unknown, or interacting with external JavaScript). Type Assertion allows you to tell the compiler to treat a variable as a specific type. It’s purely a compile-time construct and has no runtime effect; it doesn’t perform any conversion or checking at runtime.

There are two syntaxes:

  • Angle-bracket syntax: <Type>value
  • as syntax: value as Type (Preferred, especially in JSX/TSX files where angle brackets conflict with HTML/XML syntax).

Use type assertions cautiously, only when you are certain about the type, as they bypass standard type checking.

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

Scope determines the accessibility of variables within your code. TypeScript, leveraging let and const, primarily uses:

  • Global Scope: Variables declared outside any function or block. In modules, top-level variables are scoped to the module, not truly global unless attached explicitly to the global object (e.g., window in browsers, discouraged).
  • Module Scope: Variables declared at the top level of a module file (.ts file with import or export) are accessible only within that module, unless exported.
  • Function Scope: Variables declared inside a function are typically accessible only within that function (applies also to var).
  • Block Scope: Variables declared with let or const inside a block (e.g., if, for, {}) are only accessible within that specific block.
// 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)

Understanding block scope with let and const is crucial for preventing common errors associated with the older var keyword’s function scoping and hoisting behavior.