TypeScript Type Inference
Type inference is TypeScript's ability to detect the type of a variable automatically, without the developer writing a type annotation. When a value is assigned at the time of declaration, TypeScript looks at that value and figures out the type on its own. This keeps code clean while still providing full type safety.
How Type Inference Works
When TypeScript sees a declaration like let score = 90, it reads the value 90 and concludes that score must be of type number. No annotation needed — TypeScript infers it automatically.
let score = 90;
| |
| +---- TypeScript reads this value
| and concludes: type is number
+------------- Variable name
After inference, the variable is locked to that type — just as if the type was written explicitly.
let score = 90; // TypeScript infers: number score = 95; // Allowed — still a number score = "high"; // Error: Type 'string' is not assignable to type 'number'
Inference for All Basic Types
let productName = "Laptop"; // inferred as string let itemPrice = 45999; // inferred as number let inStock = true; // inferred as boolean let discount = 0.10; // inferred as number let category = null; // inferred as null // All these behave exactly as if types were written: // let productName: string = "Laptop"; // let itemPrice: number = 45999;
With Annotation vs Without Annotation
| Style | Code | Type Safety |
|---|---|---|
| With annotation | let age: number = 25; | Full |
| Without annotation (inference) | let age = 25; | Full |
| No annotation, no value | let age; | None — type becomes any |
Declaring a variable without a value and without a type annotation results in the type any, which disables type checking for that variable. This is the one situation where writing the type explicitly becomes important.
let userInput; // Type: any (unsafe) let userInput: string; // Type: string (safe — inferred when assigned)
Inference in Functions
TypeScript infers the return type of a function from the value the function returns. Writing the return type explicitly is optional when the function body makes it obvious.
// TypeScript infers return type as number
function multiply(a: number, b: number) {
return a * b;
}
let result = multiply(4, 5);
// result is inferred as number
console.log(result); // 20
function multiply(a: number, b: number) {
|
TypeScript reads the return statement
"return a * b" → both are numbers
Therefore return type = number ✓
Contextual Typing
TypeScript also infers types from context — the situation in which a value is used. This is called contextual typing.
// TypeScript knows addEventListener's callback receives a MouseEvent
document.addEventListener("click", function(event) {
// TypeScript infers: event is of type MouseEvent
console.log(event.clientX); // Works — clientX exists on MouseEvent
console.log(event.volume); // Error — volume does not exist on MouseEvent
});
TypeScript infers the type of event from the fact that it is a click event handler. No annotation needed.
Inference with Arrays
let scores = [85, 90, 78, 95];
// TypeScript infers: number[]
let names = ["Riya", "Kiran", "Dev"];
// TypeScript infers: string[]
scores.push(100); // Allowed
scores.push("A+"); // Error: Argument of type 'string' is not assignable to type 'number'
Inference with Objects
let book = {
title: "Clean Code",
pages: 431,
available: true
};
// TypeScript infers the object type as:
// { title: string; pages: number; available: boolean }
book.title = "Refactoring"; // Allowed
book.pages = 448; // Allowed
book.author = "Martin"; // Error: Property 'author' does not exist
When to Write Type Annotations Explicitly
Type inference handles most situations well. Use explicit annotations in these cases:
| Situation | Example | Reason |
|---|---|---|
| Variable declared without a value | let userId: number; | TypeScript cannot infer without a value |
| Function parameters | function greet(name: string) | TypeScript never infers parameter types |
| Complex return types | function getData(): User[] | Makes code more readable and clear |
| Mixed-type scenarios | let id: number | string; | Union types need explicit declaration |
Inference Flow Diagram
Does the variable have a value at declaration?
|
+-------+-------+
| |
YES NO
| |
TypeScript infers Is there a type annotation?
the type |
| +-------+-------+
| | |
| YES NO
| | |
| Type is set Type becomes "any"
| from annotation (type checking OFF)
|
Type checking ON automatically
Practical Example
// Inference in a real scenario — no annotations needed
let courseName = "TypeScript Basics";
let totalLessons = 10;
let isFree = false;
let rating = 4.8;
function describeCourse() {
return courseName + " | Lessons: " + totalLessons + " | Free: " + isFree;
}
let description = describeCourse();
// TypeScript infers description as string
console.log(description);
// Output: TypeScript Basics | Lessons: 10 | Free: false
console.log(rating + 0.1);
// Output: 4.9 (rating correctly treated as number)
