No types written
Look at this file: not one type is written. Yet TypeScript knows what kind of value every variable holds. It works the types out from the code itself. That is called type inference.
Inferring each line
tsc, the TypeScript checker, reads line 1. The starting value 3 is a number, so count gets the type number. tsc remembers it, just as if you had written let count: number = 3.
Line 2 works the same way. "apples" is text in quotes, a string, so label gets the type string. Each name's type comes from the value it starts with.
Line 3 has no plain value: it is count * 2. tsc looks up count, already a number. A number times 2 is a number, so total is a number. Inference works through whole expressions.
A const can never get a new value, so tsc picks the narrowest type: exactly "kg". A type that is one exact value is called a literal type. With let, the same line would infer string.
A value that does not fit
Line 5 sets count = "three". tsc compares the new value with the type it remembered for count on line 1. "three" is a string, but count is a number.
So tsc reports error TS2322 on line 5: Type 'string' is not assignable to type 'number'. You never wrote number, yet the inferred type still caught the mistake before the program ran.
Change line 5 to count = 4 and run tsc again. 4 is a number, it matches count's type, so there are no errors. count stays a number for its whole life.
In your editor
Editors show what tsc inferred. Hover over count in VS Code and it says let count: number. Write types yourself only where nothing can be inferred, such as function parameters.
What happens
;; step 1/9 · no-types infer.ts 1 let count = 3; 2 let label = "apples"; 3 let total = count * 2; 4 const unit = "kg"; 5 count = "three"; no : number no : string anywhere tsc will work every type out by itself
A function parameter with no annotation is not inferred from how you call the function: it becomes any, which the noImplicitAny setting (on in strict mode) reports as an error. The exception is contextual typing, such as a callback passed to forEach, where TypeScript knows the type from where the function goes. The error text, the four inferred types and the hover text were checked with TypeScript 5.9 (tsc and its checker) on this exact file.