Variables and Types in TypeScript
Learn variable declarations, primitive types, type inference, unions, and type conversions in TypeScript with Docker-ready examples
TypeScript is a typed superset of JavaScript, and its type system is where the language earns its keep. While JavaScript will happily let you assign any value to any variable and worry about it later, TypeScript checks your work at compile time — catching whole classes of bugs before the code ever runs.
Variables in TypeScript are declared with the same let, const, and (legacy) var keywords from JavaScript, but each binding can carry an optional type annotation. The compiler also performs aggressive type inference: if you write let count = 0, TypeScript already knows count is a number. You only need to spell out types when inference isn’t enough or when documenting an interface.
The type system is structural (a value matches a type if it has the right shape, regardless of how it was declared) and strong (no implicit coercions between unrelated types). It also models JavaScript’s quirks faithfully: null and undefined are distinct types, and with strict mode enabled, the compiler forces you to handle them explicitly.
This tutorial covers variable declarations, the primitive types, literal and union types, immutability with const and readonly, and how type conversions work in practice.
Variable Declarations and Primitive Types
Create a file named variables.ts:
| |
A few things worth highlighting:
numbercovers everything numeric, integer or float — there is no separateinttype. Usebigint(with thensuffix literal) when you need integers larger than2^53 - 1.constblocks reassignment, not mutation.const xs = [1, 2]; xs.push(3)is legal because the binding still points to the same array.- Tuples are arrays whose length and per-position types are tracked by the compiler.
Type Inference, Unions, and Literal Types
TypeScript’s most distinctive feature is the way the type system narrows as you check values. A union type like string | number lets a variable hold either, and conditional checks teach the compiler which one is present at each point.
Create a file named inference.ts:
| |
Literal types and unions together replace the role enums play in many other languages — they describe a fixed set of valid values, and the compiler enforces it.
Type Conversions and Strict Null Handling
JavaScript is famous for surprising implicit conversions. TypeScript doesn’t change the runtime behavior, but it does require explicit conversions where the types don’t line up. With strict mode, it also forces you to acknowledge null and undefined.
Create a file named conversions.ts:
| |
Three TypeScript-specific touches in this example are worth flagging:
?:on a property marks it optional. The field’s type effectively becomesT | undefined.??(nullish coalescing) returns the right-hand side only when the left side isnullorundefined, unlike||which also triggers on empty strings and zero.as T(type assertion) tells the compiler to trust you — useful at boundaries where you know more than the type system, but it does not perform a runtime check.
Running with Docker
| |
The npx -y ts-node <file> command compiles the TypeScript and executes it in one step, with no tsconfig.json required for these standalone scripts.
Expected Output
Running variables.ts:
counter = 1
greeting = Hello, TypeScript!
pi = 3.14159
language = TypeScript
active = true
big = 9007199254740993
summary = Ada is 42 (ready: true)
scores = [95, 87, 76]
pair = [age, 30]
nothing = null
notSet = undefined
tag type = symbol
Running inference.ts:
id (string form) = abc-123, length = 7
id (number form) = 42, doubled = 84
string of length 5
number with value 7.50
direction = east
mode = production
status = active
Running conversions.ts:
Number("123") = 123
parseInt("42px", 10) = 42
parseFloat("3.14abc")= 3.14
255 -> "255", hex "ff", fixed "255.00"
Boolean("") = false
Boolean("text") = true
Boolean(0) = false
Boolean(1) = true
u1 -> Grace
u2 -> Countess
asserted length = 10
Key Concepts
letis mutable,constis not — andconstdoesn’t make objects deeply immutable, only the binding itself.- Type inference is aggressive — write annotations only when they document an interface or when inference doesn’t know enough.
numberis the only general numeric type; reach forbigint(with thenliteral suffix) when integers may exceed2^53 - 1.- Union types (
A | B) let a value be one of several types; the compiler narrows the type as you check it withtypeofor equality. - Literal types (
"north" | "south") constrain a value to a fixed set, replacing many traditional enum use cases. nullandundefinedare distinct types; understrictmode the compiler forces you to handle the possibility that a value is missing.- Conversions are explicit — use
Number(...),String(...),Boolean(...),parseInt, or.toString(radix)rather than relying on implicit coercion. as Tis a type assertion, not a cast — it changes the compiler’s view but does not check or transform the value at runtime.
Comments
Loading comments...
Leave a Comment