Module Recap
Module 06 completed the TypeScript Foundations concept track. You now have the full toolkit: a type system that does not just describe values but actively refines them as your code branches and checks. Here is what to carry forward.
What you learned
Section titled “What you learned”typeof guards — narrow primitive types with typeof value === 'string'. Caught errors are unknown in strict TypeScript — narrow with instanceof Error before accessing .message.
instanceof guards — narrow class instances to their specific type inside the branch. The primary tool for error handling in catch blocks.
The in operator — check whether a property exists on an object and narrow the union accordingly. The right tool when types do not share a discriminant, and for validating unknown data from external sources.
Discriminated unions — a shared literal property (the discriminant) tells TypeScript exactly which union member you are working with. switch on the discriminant enables exhaustive handling. Invalid states become unrepresentable.
Type predicates — value is T return types propagate narrowing through function boundaries. Correct for encapsulated validation logic, Array.filter with narrowed output, and any reusable check on unknown data.
unknown, any, and never — unknown forces narrowing before use (safe uncertainty). any disables checking (escape hatch, use sparingly). never is the bottom type — values that cannot exist, and the key to exhaustive switch checking via assertNever.
How narrowing appears in AceIt
Section titled “How narrowing appears in AceIt”| Location | Technique | Purpose |
|---|---|---|
Every catch block in main.ts | instanceof Error | Access .message safely on an unknown error |
loadHighScore in quiz.ts | Type predicate isHighScore | Validate JSON.parse output before casting to HighScore |
fetchQuestions in api.ts | === ResponseCode.Success | Discriminate on the numeric API response code |
buildUrl in api.ts | Truthiness / typeof | Only append difficulty param when it is not undefined |
render function (if using QuizState) | switch on status | Route to the correct screen for each quiz state |
assertNever in render | never | Catch unhandled QuizState members at compile time |
The complete narrowing toolkit
Section titled “The complete narrowing toolkit”// typeof — primitivesif (typeof err === 'string') { /* err is string */ }
// instanceof — class instances and errorsif (err instanceof Error) { /* err is Error */ }
// in — property existenceif ('score' in value) { /* value has score property */ }
// Discriminated union switchswitch (state.status) { case 'active': /* state is { status: 'active'; question: ...; } */ break;}
// Type predicatefunction isHighScore(v: unknown): v is HighScore { /* ... */ }
// unknown — safe entry for external dataconst parsed: unknown = JSON.parse(raw);
// never — exhaustive checkingdefault: assertNever(state); // compile error if a case is missingKey terms
Section titled “Key terms”| Term | What it means |
|---|---|
| Narrowing | Refining a broad type to a specific one inside a conditional branch |
| Type guard | A check that causes TypeScript to narrow — typeof, instanceof, in, or a predicate |
| Discriminant | The shared property in a discriminated union with a unique literal value per member |
| Type predicate | A function with return type value is T — propagates narrowing through function boundaries |
unknown | A value whose type is not yet determined — must narrow before use |
any | Disables type checking — use only at explicit trust boundaries |
never | The bottom type — no value can have this type; used for exhaustive checking |
assertNever | A function that accepts never and throws — makes unhandled union cases compile errors |
What is next
Section titled “What is next”Module 07 — AceIt Project Build →
Module 07 assembles everything. You will scaffold the project from scratch, write types.ts with all interfaces and type aliases, implement api.ts with the generic fetchJson<T>, build QuizEngine in quiz.ts, wire the DOM in ui.ts, and connect it all in main.ts. Every TypeScript concept from Modules 01–06 appears in the finished app.