Types and values¶
This lesson covers the primitive types, type inference, literal types, and the difference between any, unknown, and type assertions.
Primitive types¶
TypeScript builds on JavaScript primitives. Each value can be annotated with a type.
const name: string = 'Ada'
const year: number = 2024
const active: boolean = true
const nothing: null = null
const notDefined: undefined = undefined
| Type | Examples | Notes |
|---|---|---|
string |
'hello', `" |
|
| " | ||
| ` | Text values | |
number |
42, -3.14, NaN |
All numbers are number |
boolean |
true, false |
Logical values |
null |
null |
Intentional absence |
undefined |
undefined |
Uninitialized value |
symbol |
Symbol('id') |
Unique keys |
bigint |
100n |
Arbitrary-size integers |
Inference¶
TypeScript often figures out the type from the value. You do not need to annotate everything.
const name = 'Ada' // inferred as string
const count = 12 // inferred as number
const settings = { // inferred as { dark: boolean }
dark: true,
}
Add an annotation when the type is not obvious or when you want to document a contract.
Without the annotation, an empty array becomes any[] and loses type safety.
Literal types¶
A literal type represents one exact value.
Using let with a string literal widens the type to string unless you add an explicit type.
any, unknown, and never¶
any turns off type checking. Use it as a last resort.
unknown is safer. You must prove the type before using it.
function logLength(value: unknown): void {
if (typeof value === 'string') {
console.log(value.length)
}
}
never means a value can never occur. It often appears in exhaustive checks or functions that always throw.
Type assertions¶
An assertion tells the compiler to treat a value as a specific type. It does not convert or validate the value.
Warning
A type assertion does not check the actual value. If the element is not an input, the program can crash. Validate data from the DOM, network, or files when the source is untrusted.
Type aliases¶
Give a type a reusable name with type.
type UserId = string
type Role = 'admin' | 'editor' | 'viewer'
type User = {
id: UserId
role: Role
}
Type aliases can describe primitives, unions, tuples, and objects. They are useful for making intent explicit.
Hands-on: validate a form input¶
- In your project, create
src/form.ts. - Declare a variable
rawInput: unknownand assign a string value. - Write a function
toUpperCase(value: unknown): stringthat: - returns the uppercased value if
typeof value === 'string' - throws an error otherwise
- Call
toUpperCase(rawInput)andconsole.logthe result. - Try passing a
numberand watch the function reject it at runtime while TypeScript still accepts the call because ofunknown. - Change the parameter to
value: stringand observe how the call site now gets a compiler error for the number.
When should you use unknown instead of any?
Use unknown whenever you receive data you cannot trust. It forces you to check the shape before using it.