ZetCode

TypeScript Variables

last modified October 15, 2026

A variable is a named storage for a value. TypeScript declares variables with the same keywords as JavaScript: let, const, and the older var. In addition, every variable has a type, either written explicitly as a type annotation or inferred by the compiler from the initial value. The type determines which values the variable can hold and which operations are allowed on it.

Basic Variable Declarations

A type annotation is written after the variable name, separated by a colon.

basic_variables.ts
let age: number = 30;
const userName: string = "Alice";
var isActive: boolean = true;

age = 31;
isActive = false;

console.log(age, userName, isActive);

The age variable is declared with let, so it can be reassigned later. The userName variable is declared with const and must keep its value. The var keyword also declares a reassignable variable, but it has different scoping rules, shown below, and is not used in modern code.

The annotations number, string, and boolean restrict the values. Assigning a string to age would be a compile-time error.

$ npx tsx basic_variables.ts
31 Alice false

Type and Constant Errors

The compiler reports both a value of a wrong type and an attempt to reassign a constant.

variable_errors.ts
let count: number = 10;
count = "ten";

const limit = 100;
limit = 200;

The first error comes from the type annotation, the second from the const declaration. In JavaScript, the second one would only be detected at runtime, where it throws a TypeError.

$ npx tsc --noEmit
variable_errors.ts(2,1): error TS2322: Type 'string' is not assignable to type 'number'.
variable_errors.ts(5,1): error TS2588: Cannot assign to 'limit' because it is a constant.

Block Scope

Variables declared with let and const exist only inside the block in which they are declared. A var variable belongs to the whole function.

scope.ts
function demo(): void {
    if (true) {
        var functionScoped = "var";
        let blockScoped = "let";
        console.log(functionScoped, blockScoped);
    }

    console.log(functionScoped);
    // console.log(blockScoped);  // Error: Cannot find name 'blockScoped'
}

demo();

const callbacks: (() => number)[] = [];

for (let i = 0; i < 3; i++) {
    callbacks.push(() => i);
}

console.log(callbacks.map(f => f()));

The functionScoped variable is still visible after the if block, which is a common source of bugs. The commented line would not compile, because blockScoped does not exist outside the block.

In the loop, let creates a new i for every iteration, so each callback remembers its own value and the result is [0, 1, 2]. With var, all three callbacks would share one variable and return 3.

$ npx tsx scope.ts
var let
var
[ 0, 1, 2 ]

Type Inference

When a variable is initialized, TypeScript infers its type from the value. An annotation is then usually unnecessary.

type_inference.ts
let score = 95;
const message = "Hi";
let tags = ["typescript", "web"];
let point = { x: 10, y: 20 };

score = 100;
tags.push("tutorial");

console.log(score, message, tags, point.x + point.y);

The compiler infers score as number, tags as string[], and point as { x: number; y: number }. Because message is a constant, its type is the literal type "Hi": a const can never hold another value.

Inference works only from the initial value. A variable declared without a value, such as let result;, should get an annotation; otherwise its type is determined by later assignments or becomes any.

$ npx tsx type_inference.ts
100 Hi [ 'typescript', 'web', 'tutorial' ] 30

Using a Variable Before Assignment

A variable declared with a type but without a value cannot be read until a value is assigned.

uninitialized.ts
let total: number;

console.log(total);

The compiler tracks assignments through the control flow. This prevents reading undefined from a variable whose type says number.

$ npx tsc --noEmit
uninitialized.ts(3,13): error TS2454: Variable 'total' is used before being assigned.

Union Types

A union type allows a variable to hold values of several types. The types are separated with |.

union_types.ts
let id: string | number;

id = "ABC123";
console.log(id, typeof id);

id = 123;
console.log(id, typeof id);

function formatId(value: string | number): string {
    return typeof value === "number" ? value.toString().padStart(6, "0") : value;
}

console.log(formatId("ABC123"), formatId(42));

The id variable accepts both strings and numbers. Only operations common to both types are allowed on a union directly. To use padStart on the number, formatId first checks the type with typeof; this is called narrowing and is covered in the type guards tutorial.

$ npx tsx union_types.ts
ABC123 string
123 number
ABC123 000042

Literal Types

A literal type allows only one specific value. A union of literal types restricts a variable to a fixed set of values.

literal_types.ts
let accountStatus: "active" | "inactive" | "banned";

accountStatus = "active";
console.log(accountStatus);

accountStatus = "banned";
console.log(accountStatus);

// accountStatus = "pending";  // Error: Type '"pending"' is not assignable

Only the three listed strings can be assigned. Editors also offer them as completions. Unions of string literals are a lightweight alternative to enums.

$ npx tsx literal_types.ts
active
banned

Arrays and Tuples

An array type is written as the element type followed by []. A tuple is an array with a fixed length and a known type for each position.

arrays_tuples.ts
let numbers: number[] = [1, 2, 3];
let person: [string, number] = ["Alice", 30];

numbers.push(4);
person[1] = 31;

console.log(numbers);
console.log(person);
console.log(`${person[0]} is ${person[1]}`);

The numbers array can grow, but only with numbers. The person tuple has exactly two elements: a string and a number. Assigning a string to person[1] would be an error. See the arrays and tuples tutorials for details.

$ npx tsx arrays_tuples.ts
[ 1, 2, 3, 4 ]
[ 'Alice', 31 ]
Alice is 31

Objects and Interfaces

The type of an object variable describes its properties. An interface gives such a type a name.

objects_interfaces.ts
interface User {
    name: string;
    age: number;
}

const user: User = { name: "Bob", age: 25 };

user.age = 26;
console.log(user);

The object must have both properties with the right types. Note that const only prevents assigning a different object to the variable; the properties of the object can still be changed, as with user.age here. To prevent that, mark the properties as readonly.

$ npx tsx objects_interfaces.ts
{ name: 'Bob', age: 26 }

Enums

An enum defines a set of named constants. The variable then holds one of them.

enums.ts
enum Status {
    Active = "ACTIVE",
    Inactive = "INACTIVE",
}

let currentStatus: Status = Status.Active;
console.log(currentStatus);

currentStatus = Status.Inactive;
console.log(currentStatus === Status.Inactive);

The members of a string enum have the string values given in the declaration. Unlike most TypeScript features, an enum produces JavaScript code. A union of literal types or an object with as const are common alternatives.

$ npx tsx enums.ts
ACTIVE
true

Type Aliases

The type keyword gives a name to any type, so that it can be reused for many variables.

type_aliases.ts
type Point = {
    x: number;
    y: number;
};

type Id = string | number;

let startPoint: Point = { x: 0, y: 0 };
const endPoint: Point = { x: 3, y: 4 };
let orderId: Id = 1001;

const distance = Math.hypot(endPoint.x - startPoint.x, endPoint.y - startPoint.y);
console.log(startPoint, endPoint, distance, orderId);

The Point alias describes an object and Id a union. Both variables of type Point share the same definition; changing it in one place updates all of them.

$ npx tsx type_aliases.ts
{ x: 0, y: 0 } { x: 3, y: 4 } 5 1001

Best Practices

Source

TypeScript Handbook: Variable Declaration

This tutorial covered variables in TypeScript. Declare them with const or let, let the compiler infer simple types, and annotate where the type is not obvious from the value.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all TypeScript tutorials.