TypeScript often understands a variable type from the assigned value. This is called type inference. If you write const course = "TypeScript", TypeScript knows the value is a string-like value without needing an annotation.
Use inference when the type is obvious. It keeps code cleaner and avoids repeating information that TypeScript already knows. Good TypeScript code is not the code with the most annotations; it is the code where the important contracts are clear.
| Declaration | Inferred Type | Reason |
|---|---|---|
const course = "TypeScript" | "TypeScript" | The binding cannot be reassigned. |
let lessons = 15 | number | The variable can later hold another number. |
let published = true | boolean | The variable can later hold true or false. |
const course = "TypeScript";
let lessons = 15;
let published = true;
lessons = 16;
published = false;
// lessons = "fifteen"; // Error
console.log(course, lessons, published);
A type annotation explicitly tells TypeScript what type a variable should hold. Annotations are helpful when a variable starts empty, when a function returns a broad type, or when you want to document intent clearly.
Avoid annotating every obvious value. For example, const name: string = "Admin" is usually less useful than letting TypeScript infer it. Save annotations for places where they add clarity or safety.
let username: string;
let totalViews: number = 0;
let tags: string[] = [];
username = "admin";
totalViews += 100;
tags.push("typescript");
const means the variable binding cannot be reassigned. TypeScript can often infer a narrower literal type for const values because the value cannot change.
let allows reassignment, so TypeScript usually infers a wider type. This difference matters when you want only specific string or number values to be allowed.
const role = "admin"; // type is "admin"
let status = "draft"; // type is string
type PostStatus = "draft" | "published" | "archived";
let postStatus: PostStatus = "draft";
postStatus = "published";
// postStatus = "deleted"; // Error
Sometimes a variable is declared before its value is known. In that case, add an annotation so TypeScript understands what the variable will eventually contain.
If the value may genuinely be missing, include null or undefined in the type and handle that case before using the value. This makes missing data visible instead of accidental.
type User = { id: number; name: string };
let selectedUser: User | null = null;
function selectUser(user: User): void {
selectedUser = user;
}
if (selectedUser === null) {
console.log("No user selected");
} else {
console.log(selectedUser.name);
}
Empty arrays and empty objects often need help from annotations. Without context, TypeScript may infer a type that is too narrow or not useful for the values you plan to store later.
Name important object shapes with an interface or type alias. This keeps variables readable and prevents the same inline object type from being repeated across several files.
type Tutorial = {
id: number;
title: string;
published: boolean;
};
const tutorials: Tutorial[] = [];
tutorials.push({
id: 1,
title: "TypeScript Variables",
published: true,
});
any turns off type checking for a value. It can be useful during migration from JavaScript or when temporarily integrating untyped libraries, but it should not become the default escape hatch.
Prefer unknown for values that truly come from outside your program. With unknown, TypeScript forces you to check the value before using it.
let responseData: unknown = JSON.parse('{"name":"Admin"}');
if (
typeof responseData === "object" &&
responseData !== null &&
"name" in responseData
) {
console.log(responseData.name);
}
Good TypeScript does not mean adding the most annotations possible. It means adding useful information where it improves safety or communication.
Let local values infer naturally, annotate public function inputs and outputs, and name important object shapes with interfaces or type aliases.
const can infer narrower literal types than let.
null or undefined when needed.
unknown over any for uncertain external data.
Explore 500+ free tutorials across 20+ languages and frameworks.