TypeScript 4 ๐ท Basic Types โ string, number, boolean, null, undefined
TypeScript’s type system starts with a small set of primitive types: string, number, boolean, null, and undefined. These are the atoms โ every more complex type is built by combining them. They map directly to JavaScript’s runtime primitives, but TypeScript gives them a compile-time identity that the runtime doesn’t have. Understanding them properly is not just “know the names” โ it’s knowing how they interact, how null and undefined behave under strict mode, how inference picks them, and where the common traps are.
Key point: These five types are the foundation of everything else. Every object type, every union, every generic resolves down to a combination of these. Get them right and the rest of TypeScript is easier. Get them wrong โ especially null and undefined โ and every subsequent chapter becomes harder than it needs to be.
string
A string is a sequence of characters. At runtime it’s JavaScript’s string primitive; at compile time it’s TypeScript’s string type.
let greeting: string = 'Hello';
let name = 'Alice'; // inferred as string
const literal = 'fixed'; // inferred as 'fixed' (literal type)
greeting = "Single or double"; // both work
greeting = `Template ${name}`; // template literals are strings too
What string supports:
- Concatenation โ
a + b - Template literals โ
`${x}` - All
String.prototypemethods โ.toUpperCase(),.slice(),.includes() - Comparison โ
===,<,>
What it doesn’t do:
'1' + 1is'11'at runtime (string wins). TypeScript doesn’t prevent this.- You can’t assign a
numberto astringvariable. String(the object wrapper) is not the same asstring(the primitive). Usestring.
Important distinction โ string vs String:
let a: string = 'hello'; // โ
primitive
let b: String = 'hello'; // โ
object wrapper โ avoid
let c: string = new String('x'); // โ String object, not primitive
Almost always use lowercase string. The capital String is the object wrapper that exists in JavaScript and rarely appears in well-written TypeScript.
Why the lowercase:
stringrefers to the primitive type โ the one created by literals like'hello'.Stringrefers to the constructor function and its object instances. They behave differently at runtime (typeof 'x'is'string',typeof new String('x')is'object'). You want the primitive.
number
A number is any numeric value. JavaScript has one numeric type โ a 64-bit floating point โ so TypeScript has one too.
let count: number = 42;
let price = 19.99; // inferred as number
let hex = 0xFF; // 255
let binary = 0b1010; // 10
let octal = 0o755; // 493
let big = 1_000_000; // underscores for readability
let nan = NaN; // number
let inf = Infinity; // number
Everything numeric is a number: integers, floats, hex, binary, NaN, Infinity. There’s no int or float in TypeScript.
The floating-point caveat: 0.1 + 0.2 !== 0.3. TypeScript doesn’t warn about this โ it’s a JavaScript runtime issue, and TypeScript preserves JavaScript semantics. If exact decimal math matters, use a library like decimal.js or big.js.
bigint โ when number isn’t enough:
let huge: bigint = 9007199254740991n;
let alsoHuge = 10n; // bigint literal
bigint is a separate type. It’s not interchangeable with number, and you can’t mix them in arithmetic without an explicit conversion. Use it when you need integers beyond Number.MAX_SAFE_INTEGER โ rare in everyday work, essential for crypto, IDs, and finance.
Numeric literal types: Every specific number is also a type.
let five: 5 = 5; // only 5 is assignable
let dice: 1 | 2 | 3 | 4 | 5 | 6; // union of literals
Literal types are covered in a later chapter, but they exist for number and string alike.
Why “everything is a number”: JavaScript’s number type was designed for simplicity โ one numeric type, floating-point semantics, no integer/float split. TypeScript preserves that. It means fewer surprises when moving between the two languages, but it also means you don’t get automatic precision guarantees.
boolean
A boolean is true or false. Nothing else. Under strict mode, 0, '', null, and undefined are not booleans โ they’re truthy or falsy values, but TypeScript requires an actual boolean.
let isActive: boolean = true;
let isLoading = false; // inferred as boolean
let literal: true = true; // literal type, only true
isActive = false;
isActive = 1; // โ number is not boolean
isActive = 0; // โ number is not boolean
Truthy/falsy vs boolean: In JavaScript, if (value) runs when value is truthy. In TypeScript with strict mode, that’s still fine inside an if, but you can’t assign a non-boolean where a boolean is expected.
const name = 'Alice';
const hasName: boolean = name; // โ string is not boolean
const hasName: boolean = !!name; // โ
double negation coerces
const hasName: boolean = name !== ''; // โ
explicit comparison
The idiomatic way to produce a boolean from a possibly-falsy value is !! or an explicit comparison. Boolean(value) also works but is noisier.
Why this strictness matters: Treating 0 or '' as booleans hides bugs. A user with age = 0 shouldn’t be treated as “no age.” TypeScript forces you to be explicit โ if (user.age !== undefined) rather than if (user.age) โ which catches real logic errors.
Why booleans are stricter than JavaScript: JavaScript’s loose truthiness is convenient but imprecise. TypeScript’s
booleantype requires an actual boolean, soif (user)whereuseris an object still works (narrowing handles it), but assigning0to a variable typedbooleanfails. The rule: usebooleanwhen you mean a boolean, not “truthy.”
null and undefined
These are the two “absence” types. They’re separate types in TypeScript โ and under strict mode, they’re not assignable to anything except their own type or unknown/any.
let a: null = null;
let b: undefined = undefined;
The fundamental question: What’s the difference?
undefinedโ “not yet assigned” โ a variable that hasn’t been set, a missing property, a function that doesn’t return anything, a missing function argumentnullโ “intentionally empty” โ a value that’s deliberately set to nothing, like a database query result that found nothing, or a nullable field that was cleared
In practice, JavaScript and TypeScript blur these constantly. Many codebases use null for “explicitly absent” and undefined for “not provided.” Some use only undefined. The key is consistency โ the compiler will track either way.
Under strictNullChecks (part of strict: true):
let name: string = 'Alice';
name = null; // โ null is not assignable to string
name = undefined; // โ undefined is not assignable to string
let maybeName: string | null = 'Alice';
maybeName = null; // โ
This is the single most important behavior in modern TypeScript. Before strict null checks (and still, if you turn it off), null and undefined were assignable to everything โ leading to the runtime classic: Cannot read property 'x' of null.
Why strictNullChecks matters: Without it, every value might be null, and you can’t know. With it, TypeScript tracks which variables might be null and forces you to handle the null case before using them. It’s the biggest single improvement in type safety that TypeScript offers.
Why strict null checks exist: Tony Hoare called
nullthe “billion-dollar mistake” โ the source of countless crashes. TypeScript’s response is to make nullability explicit in the type system. If a value can benull, the type says so. If it can’t, using it is safe. That distinction catches crashes at compile time.
Optional properties, parameters, and returns
undefined shows up in three specific places: optional object properties, optional function parameters, and functions that don’t return a value.
Optional properties โ ?:
interface User {
id: number;
nickname?: string; // string | undefined
}
const u1: User = { id: 1 };
const u2: User = { id: 2, nickname: 'Al' };
u1.nickname; // string | undefined
u1.nickname.length; // โ possibly undefined
u1.nickname?.length; // โ
The ? adds undefined to the type. A property with ? may be absent โ accessing it gives string | undefined.
Optional parameters โ ?:
function greet(name: string, title?: string): string {
return title ? `${title} ${name}` : name;
}
greet('Alice'); // โ
greet('Alice', 'Dr.'); // โ
greet('Alice', undefined); // โ
explicit undefined
Optional parameters must come after required ones. title is string | undefined inside the function.
Optional return โ implicit undefined:
function log(message: string): void {
console.log(message);
// returns undefined at runtime, but declared as void
}
void means “this function doesn’t return a useful value.” At runtime, it returns undefined, but the type is void โ you can’t use the result.
void vs undefined:
function a(): void { } // doesn't return a value
function b(): undefined { } // returns undefined explicitly
function c(): undefined { return undefined; } // must return undefined
Use void for functions whose return value is meaningless. Use undefined (rarely) when a function must literally return undefined.
Why
voidis different fromundefined: Avoidfunction is one where the caller shouldn’t use the return value.undefinedis a real value. The distinction matters in callbacks and generics:Array<number>.forEach(fn)expectsfnto returnvoid, but a function that returns a value is still assignable (the result is just ignored). TypeScript handles this specifically forvoid.
Type inference for basics
TypeScript infers types from initial values. You don’t annotate every variable.
let s = 'hello'; // string
let n = 42; // number
let b = true; // boolean
let nl = null; // null (widened)
let ud = undefined; // undefined (widened)
let vs const widening:
let a = 'hello'; // string
const b = 'hello'; // 'hello' (literal)
const produces a literal type โ the exact value. let widens to the general type. That distinction matters for discriminated unions and object shapes.
When to annotate:
| Situation | Annotate? |
|---|---|
| Simple initializer | โ Let inference work |
| Function parameters | โ Always |
| Function returns | โ ๏ธ Sometimes โ for public APIs |
| Empty variable | โ Can’t infer from nothing |
| Complex expressions | โ ๏ธ If inference is unclear |
Example with no annotation:
const user = { name: 'Alice', age: 30 };
// Inferred: { name: string; age: number }
TypeScript figures out the shape. You don’t need an interface unless you plan to reuse the shape or want to constrain it.
Empty variable โ needs annotation:
let result; // any
result = 5; // still any
let typed: number; // number, uninitialized
typed = 5; // โ
let result; without an initializer is any โ avoid it. Annotate empty variables.
Why inference matters: Writing types for everything is noise. TypeScript’s whole ergonomic advantage is that you annotate where it matters (boundaries, public APIs) and let inference handle the rest. If you’re annotating every local variable, you’re fighting the language.
null vs undefined in practice
Both represent absence. Choosing between them is a style decision โ but it should be a consistent one.
Common conventions:
| Style | null means | undefined means |
|---|---|---|
| Explicit absence | Value is deliberately empty | Value was never set |
| Undefined-only | Not used | Everything absent |
| Null-only | Everything absent | Not used |
Undefined-only (modern preference):
interface User {
id: number;
nickname?: string; // string | undefined
}
function findUser(id: number): User | undefined {
return users.find(u => u.id === id); // undefined if not found
}
The reason: undefined is the default for missing properties and missing arguments, so relying on it exclusively keeps types simpler. null only appears when an external system (JSON APIs, databases) sends it.
Null-and-undefined explicitly:
type Maybe<T> = T | null | undefined;
This is often a signal that nullability is getting complicated. Prefer one or the other.
?? โ nullish coalescing:
const display = name ?? 'Anonymous';
// Uses 'Anonymous' if name is null OR undefined
?? only triggers for null and undefined. Unlike ||, it doesn’t treat 0, '', or false as “missing.”
const count = 0;
const a = count || 10; // 10 (0 is falsy)
const b = count ?? 10; // 0 (0 is not null/undefined)
?. โ optional chaining:
const city = user?.address?.city;
// undefined if user or address is null/undefined
?. short-circuits when the left side is null or undefined. It’s the safe way to access nested properties.
! โ non-null assertion (use carefully):
const el = document.getElementById('app')!;
el.innerHTML = 'Hello'; // โ
compiles โ trusts you
The ! tells TypeScript “trust me, this isn’t null.” If you’re wrong, you get a runtime crash. Use it sparingly โ only when you have information the compiler doesn’t.
Why
??and?.exist: They’re the modern way to handle nullability.||and&&are too aggressive โ||treats0and''as missing.??and?.are precise. Together with strict null checks, they make null-handling clean and safe.
A full example
A small user model that uses all the basic types.
interface User {
id: number;
name: string;
isActive: boolean;
nickname?: string; // optional โ string | undefined
deletedAt: Date | null; // explicit null if deleted
}
function displayName(user: User): string {
return user.nickname ?? user.name;
}
function isVisible(user: User): boolean {
return user.isActive && user.deletedAt === null;
}
const alice: User = {
id: 1,
name: 'Alice',
isActive: true,
deletedAt: null
};
const bob: User = {
id: 2,
name: 'Bob',
isActive: false,
nickname: 'Bobby',
deletedAt: new Date()
};
console.log(displayName(alice)); // Alice
console.log(displayName(bob)); // Bobby
console.log(isVisible(alice)); // true
console.log(isVisible(bob)); // false
Every primitive is exercised: number for IDs, string for names, boolean for status, optional nickname, and null for deletedAt. The functions handle absence with ?? and explicit === null checks.
What the compiler enforces:
idmust be a numbernamemust be a stringisActivemust be a booleannicknamemay be missing or a stringdeletedAtmust be present and either aDateornullโ notundefined
Try omitting deletedAt and TypeScript rejects it โ the property isn’t optional.
Why this shape: It models a real domain. Users have IDs, names, status flags, and sometimes a deletion date. Every primitive type maps to a real concept. That’s the whole point โ types describe your domain, not abstract mathematics.
Complete Example Session
# ============================================
# PART 1: CREATE A FILE
# ============================================
cat > basics.ts << 'EOF'
// ============================================
// STRINGS
// ============================================
let greeting: string = 'Hello';
let name = 'Alice';
const fixed = 'constant string';
// ============================================
// NUMBERS
// ============================================
let count: number = 42;
let price = 19.99;
let hex = 0xFF;
let big = 1_000_000;
let nan = NaN;
// ============================================
// BOOLEANS
// ============================================
let isActive: boolean = true;
let isLoading = false;
// ============================================
// NULL AND UNDEFINED
// ============================================
let nothing: null = null;
let missing: undefined = undefined;
// ============================================
// UNION WITH NULL
// ============================================
let maybeName: string | null = 'Alice';
maybeName = null;
// ============================================
// OPTIONAL PROPERTIES
// ============================================
interface User {
id: number;
name: string;
isActive: boolean;
nickname?: string;
deletedAt: Date | null;
}
const alice: User = {
id: 1,
name: 'Alice',
isActive: true,
deletedAt: null
};
// ============================================
// NULL-HANDLING OPERATORS
// ============================================
const display = alice.nickname ?? alice.name;
const city = (alice as any).address?.city;
console.log(greeting, name, count, isActive, display, city);
EOF
# ============================================
# PART 2: TYPE-CHECK
# ============================================
npx tsc --noEmit basics.ts
# (no output โ no errors)
# ============================================
# PART 3: TRIGGER ERRORS
# ============================================
cat > errors.ts << 'EOF'
let s: string = 42; // โ number not assignable to string
let n: number = 'hello'; // โ string not assignable to number
let b: boolean = 1; // โ number not assignable to boolean
let name: string = 'Alice';
name = null; // โ null not assignable under strict
interface User { id: number; }
const u: User = {}; // โ missing id
EOF
npx tsc --noEmit errors.ts
# [ errors.ts:1:5 - Type 'number' is not assignable to type 'string'. ]
# [ errors.ts:2:5 - Type 'string' is not assignable to type 'number'. ]
# [ errors.ts:3:5 - Type 'number' is not assignable to type 'boolean'. ]
# [ errors.ts:6:1 - Type 'null' is not assignable to type 'string'. ]
# [ errors.ts:9:7 - Property 'id' is missing. ]
rm errors.ts
# ============================================
# PART 4: COMPILE AND RUN
# ============================================
npx tsc basics.ts
node basics.js
# [ Hello Alice 42 true Alice undefined ]
Quick Reference
The Five Primitives
| Type | Example | Notes |
|---|---|---|
string | 'hello' | Use lowercase, not String |
number | 42, 3.14 | One numeric type โ no int/float |
boolean | true, false | Under strict, no truthy coercion |
null | null | “Intentionally empty” |
undefined | undefined | “Not yet set” |
Additional Numeric Type
| Type | Example | Use when |
|---|---|---|
bigint | 10n | Beyond Number.MAX_SAFE_INTEGER |
Absence in Types
| Syntax | Type |
|---|---|
string | null | String or null |
string | undefined | String or undefined |
nickname?: string | string | undefined |
void | No meaningful return |
never | Never returns (throws) |
Operators
| Operator | Purpose |
|---|---|
?? | Nullish coalescing |
?. | Optional chaining |
! | Non-null assertion |
!! | Coerce to boolean |
=== null | Explicit null check |
void vs undefined
| Return type | Meaning |
|---|---|
void | Doesn’t return useful value |
undefined | Must return undefined |
Inference
| Declaration | Inferred type |
|---|---|
let x = 'a' | string |
const x = 'a' | 'a' (literal) |
let x = 5 | number |
let x = true | boolean |
let x; | any (avoid) |
Strict Null Checks
| Behavior | With strict | Without strict |
|---|---|---|
null assignable to string | โ | โ |
undefined assignable to string | โ | โ |
| Optional props | | undefined | Often | undefined |
| Null safety | Enforced | Not enforced |
Common String Methods (typed)
| Method | Returns |
|---|---|
.toUpperCase() | string |
.slice(n) | string |
.includes(x) | boolean |
.split(sep) | string[] |
.length | number |
Common Number Methods (typed)
| Method | Returns |
|---|---|
.toFixed(n) | string |
.toString() | string |
Number.isInteger(n) | boolean |
parseInt(s) | number |
parseFloat(s) | number |
Best Practices
โ Do This:
// Let inference do its job
let count = 42; // โ
number
// Use lowercase primitives
let name: string = 'Alice'; // โ
// Enable strict null checks
"strict": true // โ
// Handle nullability with ?. and ??
const display = user.nickname ?? user.name; // โ
// Use explicit comparisons for booleans
if (name !== '') { ... } // โ
// Coerce truthy values to boolean with !!
const hasName = !!name; // โ
// Use void for no-return functions
function log(msg: string): void { console.log(msg); } // โ
// Annotate empty variables
let result: number; // โ
// Use bigint for huge numbers
let id: bigint = 9007199254740993n; // โ
โ Don’t Do This:
// Don't use String, Number, Boolean wrappers
let name: String = 'Alice'; // โ ๏ธ object wrapper
// Don't trust truthy checks for numbers
if (count) { ... } // 0 is falsy // โ ๏ธ explicit !== undefined
// Don't use `||` for defaults
const n = count || 10; // โ ๏ธ use ?? for null only
// Don't overuse non-null assertions
const el = document.getElementById('x')!; // โ ๏ธ can crash
// Don't assign null to non-nullable types
let s: string = null; // โ
// Don't leave variables untyped
let x; // โ ๏ธ implicit any
// Don't mix null and undefined randomly
interface U { a?: string; b: string | null; } // โ ๏ธ pick a convention
// Don't use `any` to silence null errors
const v = (x as any).foo; // โ
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
String vs string | Object wrapper confusion | Use lowercase |
| Loose truthy checks | 0 and '' treated as missing | Explicit !== undefined |
|| for defaults | 0 becomes fallback | Use ?? |
Forgetting ?. | Runtime null crash | Optional chaining |
Overusing ! | Hidden runtime errors | Narrow properly |
NaN comparisons | NaN !== NaN | Use Number.isNaN() |
| Float precision | 0.1 + 0.2 !== 0.3 | Use a decimal library |
Missing strictNullChecks | Null crashes | Enable strict: true |
Uninitialized let | any | Annotate |
undefined vs null mixes | Inconsistent API | Pick a convention |
Real-World Examples
1. A typed string
const name: string = 'Alice';
2. A typed number
const age: number = 30;
3. A typed boolean
const isActive: boolean = true;
4. Nullable string
let nickname: string | null = null;
5. Optional property
interface User { id: number; nickname?: string; }
6. Void function
function log(msg: string): void { console.log(msg); }
7. Nullish coalescing
const display = user.nickname ?? user.name;
8. Optional chaining
const city = user?.address?.city;
9. Non-null assertion
const el = document.getElementById('app')!;
10. Boolean coercion
const hasName = !!user.name;
11. Explicit null check
if (user.deletedAt === null) { ... }
12. Strict comparison against undefined
if (value !== undefined) { ... }
13. BigInt
const huge: bigint = 9007199254740993n;
14. Literal type
type Direction = 'north' | 'south' | 'east' | 'west';
15. Union with undefined
function find(id: number): User | undefined { ... }
16. Template literal
const msg = `Hello, ${name}!`;
17. Number formatting
const formatted = price.toFixed(2);
18. Safe number parsing
const parsed = Number.parseInt('42', 10);
19. Safe number check
if (Number.isInteger(value)) { ... }
20. Consistent absence
interface Config {
apiUrl?: string; // maybe missing
timeout: number | null; // explicit null when disabled
}
Visual: The Primitive Types
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ string โ
โ โ
โ 'hello' "world" `template ${x}` โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ number โ
โ โ
โ 42 3.14 0xFF 0b1010 1_000_000 โ
โ โ
โ (also NaN, Infinity) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ boolean โ
โ โ
โ true false โ
โ โ
โ (strict โ no truthy coercion) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ null / undefined โ
โ โ
โ null โ intentionally empty โ
โ undefined โ not yet set โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ bigint โ
โ โ
โ 10n 9007199254740993n โ
โ โ
โ (separate from number) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Visual: Strict Null Checks
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ strictNullChecks: false โ
โ โ
โ let name: string = 'Alice'; โ
โ name = null; โ
allowed โ
โ name = undefined; โ
allowed โ
โ โ
โ (null crashes hide until runtime) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ strictNullChecks: true โ
โ โ
โ let name: string = 'Alice'; โ
โ name = null; โ rejected โ
โ name = undefined; โ rejected โ
โ โ
โ let maybe: string | null = 'Alice'; โ
โ maybe = null; โ
allowed โ
โ โ
โ (null crashes caught at compile time) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Visual: Null Handling Operators
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ?? โ nullish coalescing โ
โ โ
โ a ?? b โ
โ โ
โ Uses b only if a is null or undefined โ
โ Does NOT trigger on 0, '', false โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ?. โ optional chaining โ
โ โ
โ user?.address?.city โ
โ โ
โ Short-circuits to undefined if any link โ
โ is null or undefined โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ! โ non-null assertion โ
โ โ
โ el! โ
โ โ
โ "Trust me, this isn't null" โ
โ Compiles away โ no runtime check โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Visual: Type Inference
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ let x = 'hello'; โ string โ
โ const y = 'hello'; โ 'hello' โ
โ โ
โ let n = 42; โ number โ
โ const m = 42; โ 42 โ
โ โ
โ let b = true; โ boolean โ
โ const c = true; โ true โ
โ โ
โ let empty; โ any (avoid) โ
โ let typed: number; โ number โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Visual: void vs undefined vs never
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ void โ
โ โ
โ function log(): void { } โ
โ โ no useful return value โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ undefined โ
โ โ
โ function f(): undefined { return undefined; }โ
โ โ must return undefined explicitly โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ never โ
โ โ
โ function fail(): never { throw new Error(); }โ
โ โ never returns โ code after is unreachable โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Visual: Optional Property
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ interface User { โ
โ id: number; โ
โ nickname?: string; โ
โ } โ
โ โ
โ โ id: number โ
โ โ nickname: string | undefined โ
โ โ
โ { id: 1 } โ
โ
โ { id: 1, nickname: 'Al'} โ
โ
โ { nickname: 'Al' } โ missing id โ
โ { id: 1, nickname: null} โ null not string โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Type | Represents | Under strict, assignable to |
|---|---|---|
string | Text | string only |
number | Any numeric value | number only |
boolean | true / false | boolean only |
null | Intentional absence | null only |
undefined | Not-yet-set absence | undefined only |
void | No meaningful return | Function returns only |
bigint | Arbitrary-precision integer | bigint only |
Key takeaways:
- TypeScript’s primitives mirror JavaScript’s โ
string,number,boolean,null,undefinedโ plusbigint - Use lowercase names โ
string, notString;number, notNumber numbercovers all numeric values โ integers, floats, hex, binary,NaN,Infinitybooleanunder strict mode rejects truthy/falsy values โ use!!or explicit comparisonsnullmeans “intentionally empty”;undefinedmeans “not yet set” โ pick a convention and stick to it- With
strict: true(especiallystrictNullChecks),nullandundefinedare not assignable to other types ??and?.handle nullability precisely โ??only triggers on null/undefined,?.short-circuits!asserts non-null โ use sparinglyvoidmeans “no useful return value”; it’s different from returningundefined- Inference handles most variables โ
letwidens,constproduces literal types - Optional properties (
nickname?: string) addundefinedto the type - Annotate empty variables โ
let x;isany
Remember: These five primitives โ plus bigint โ are the atoms of every TypeScript type. Get null and undefined right, and strict null checks become a superpower instead of a nuisance. Use ?? and ?. for safe access, annotate where inference can’t help, and lean on strict: true to catch the bugs that JavaScript hides until runtime. Everything else in TypeScript โ objects, arrays, generics, unions โ is built by combining these atoms.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!