TypeScript Essentials — Reading Type Errors & Avoiding any
TypeScript Essentials — Reading Type Errors & Avoiding any
🎯 After reading this lesson
By the end of this lesson, you will be able to confidently do the following three things.
- ▸✅ Replace any with unknown to restore type safety
- ▸✅ Understand interface vs type, unions, optionals, and never
- ▸✅ Use 5 Utility Types (Partial, Pick, Omit, Record, Required)
Keep these learning goals as a checklist — close the lesson once you can answer all of them.
⚠️ tsconfig prerequisite — based on strict mode
All examples assume "strict": true
When strict is off — it becomes a different language
- ▸
nullis assignable to every type → no error even if null goes into astringvariable - ▸With
noImplicitAnyoff, thexinfunction f(x)becomes implicit any → type checking is disabled - ▸Narrowing behavior for
unknown/neverbecomes looser
How to verify
Rule: New projects default to strict: true (Vite, Next.js, CRA — all of them). Always check before practicing on an existing project. If it's off, that's the cause of 99% of "why doesn't it work like in the book?" moments.
Why TypeScript saves tokens
Fact — 90% of new projects in 2026 use TypeScript
Cursor, v0.dev, Claude Code, GitHub Copilot — all generate TypeScript by default. Even if you start with JS, .ts files will be added sooner or later.
The token-saving mechanism — type information as context
When you ask AI to "write the code to call sendEmail(currentUser, welcome)":
- ▸In JS → you have to re-explain what user is and what fields it has
- ▸In TS → the AI infers everything from the interface alone. No extra explanation needed.
The type definition itself is the AI context. Extra prompting = extra tokens. TypeScript reduces both.
The 8 basic types
Why any is dangerous
any disables all of TypeScript's safety. When AI writes any, ask it to replace it with unknown.
unknown — the safe any
Forces type verification before use. The standard for API response parsing and external input.
interface vs type, unions, and optionals
interface vs type — when to use which
Rule: Use interface for object shapes, use type for everything else (unions, tuples, mappings). Many teams also follow a "type for everything" convention.
Union | — one of several types
Literal unions are most common:
Literal unions are now the standard instead of enums.
Optional ?
A ? means undefined is also allowed. Common in function parameters and DTOs.
Generic <T> — basic form
"Type as a variable" — determined at call time. Widely used in libraries (React Hooks, Array methods).
never — the unreachable type
What never is
The bottom type — a subtype of every type. Represents "a value that cannot exist." A function that can never return normally (throws or runs forever) also returns never:
Exhaustive Check — catch missing switch cases at compile time
If you add 'star' to Shape — since the switch doesn't handle it, s is narrowed to 'star' → cannot be assigned to a never variable → compile error. The compiler forces you to handle the new case.
The TypeScript equivalent of Java's sealed classes and Rust's exhaustive enum matching.
never vs void — a classic interview question
Real-world usage — the safety net for discriminated unions
Whenever you see this pattern in TypeScript code — discriminated union + never default check. Knowing this gives you a solid answer to "what makes TypeScript better than JavaScript?" in interviews.
Utility Types — 5 interview essentials
TypeScript's built-in type transformers
Create new types by transforming existing ones. These 5 cover 99% of real-world use cases.
1. Partial<T> — make all fields optional
2. Required<T> — make all fields required (opposite of Partial)
3. Pick<T, K> — select only some fields
4. Omit<T, K> — exclude some fields
5. Record<K, V> — key-value map
An alternative to enums — when the key is a union type, the compiler checks that all keys are present. Missing one causes an error.
Interview talking points — these 3 patterns appear in production every day
- ▸Partial → PATCH API DTO (
Partial<User>) - ▸Omit → remove sensitive fields (
Omit<User, 'password' | 'tokenSecret'>) - ▸Record → permission/locale/state maps (
Record<Role, Permission[]>)
Other Utility Types — useful to know
ReturnType / Awaited also come up in interviews. The answer to "how do you reuse a function's return type elsewhere?" is ReturnType.
Reading type errors, type assertions, and working with React
Read error messages slowly
The real cause is at the bottom. "'email' is missing" — the provider doesn't satisfy the receiver's type.
Type assertion as — dangerous if overused
"Trust me, this is an HTMLDivElement" — manually bypassing TypeScript's checks.
Do not overuse. Code full of as is no different from not using TypeScript at all. Narrowing (if (typeof x === ...)) or type guards should come first.
Type guards
x is User is the return type — TypeScript applies narrowing at the call site.
React component types
Defining a separate props interface is the standard approach.
useState type inference
Be explicit when null is possible — the inference may narrow to just null type and cause problems.
API response types
Specifying the return type explicitly enables automatic narrowing at the call site.
🤖 Try asking AI like this
- ▸"Add TypeScript types to this function. Don't use any — use unknown or explicit types."
- ▸"Explain this error message in plain English" (just paste it and the AI will walk you through it)
- ▸"Replace this
asassertion with a type guard"
Knowing just 5 things (interface, unions, optionals, narrowing, generics) will solve 90% of vibe coding issues.
`as` vs `as const` — two completely different tools
as — bypasses the type system (dangerous)
Manually turns off the compiler's checks. A wrong assertion blows up at runtime.
as const — fixes literal types (safe alternative)
Array → union type generation pattern — the real value of as const
Values and types are always in sync. Add 'staff' to ROLES and Role automatically becomes 'admin' | 'user' | 'guest' | 'staff'. An elegant solution to the limitations of plain enums.
Object freezing — config and constant collections
Real-world example — creating a Discriminated Union
One-line summary
- ▸as — tricks the compiler into accepting a type. Avoid it almost always.
- ▸as const — extracts exact literal types from values. Safe. Use it often.