
Set 6 is about how you talk to the TypeScript compiler: narrowing with type predicates and assertion functions, merging and extending existing declarations, writing .d.ts files and setting up large projects. Each explanation tells you what the compiler sees in that case.
How to practise: read each question and tap the option you think is correct. You will see right away whether you got it, along with a short explanation, and your score is tracked at the bottom of the screen. This set has 15 questions.
Topics covered in this set
- Type predicates and inferred predicates in filter
- Assertion functions with asserts
- never checks that also fail at runtime
- Declaration merging and module augmentation
- declare global, ambient declarations and .d.ts files
- Project references and safe use of unknown
TypeScript MCQs with answers and explanations
Q1. What is the type of v after the call?
function assertIsString(v: unknown): asserts v is string {
if (typeof v !== "string") throw new Error("Not a string");
}
assertIsString(v);
a) string
b) never
c) any
d) unknown
Q2. What does a signature like function assert(cond: unknown, msg?: string): asserts cond mean?
a) If the call returns, the condition passed in is treated as true for narrowing afterwards
b) The function returns a boolean
c) cond must be a boolean literal
d) It only works in tests
Q3. This code gives error TS2775. Why?
const assertStr = (v: unknown): asserts v is string => { ... };
assertStr(input);
a) Arrow functions cannot throw
b) Assertion functions must be called through a name with an explicit type annotation, which an inferred const does not have
c) asserts only works with classes
d) input must be any
Q4. From TypeScript 5.5, what is the type of xs?
const xs = [1, undefined, 2].filter(x => x !== undefined);
a) undefined[]
b) number[]
c) (number | undefined)[]
d) any[]
Q5. Why should an assertNever(x: never) helper also throw at runtime?
a) It is required by the compiler
b) Data from APIs or JavaScript callers can still contain values the types did not expect, so the default branch can run
c) never values are always undefined
d) Throwing improves performance
Q6. What happens with these two declarations?
interface Config { port: string }
interface Config { port: number }
a) port becomes string | number
b) port becomes never
c) Compile error: subsequent property declarations must have the same type
d) The second one wins
Q7. What does this code do?
function greet(name: string) { return "Hi " + name; }
namespace greet {
export const version = "1.0";
}
a) Overwrites the function
b) Creates two separate values
c) Compile error: duplicate identifier
d) Merges the namespace into the function, so greet.version is typed and available
Q8. To add a user property to Express's Request type, what must the augmentation file contain?
a) A copy of all Express types
b) A declare module block for the Express types package that re-opens the Request interface, inside a file that is itself a module
c) A runtime assignment to Request.prototype
d) A class that extends Request
Q9. Why is export {} often added to a file containing declare global { interface Window { analytics: Analytics } }?
a) It removes the global
b) It exports the Window type
c) It is needed for tree shaking
d) declare global is only allowed in a module, and export {} turns the file into a module
Q10. What does declare const __APP_VERSION__: string; do?
a) Defines a constant enum
b) Tells the compiler that a global with this type exists, without emitting any JavaScript
c) Imports the value from package.json
d) Creates the variable at runtime
Q11. A project gets "Cannot find module './logo.svg'". What declaration fixes the import?
a) import type svg from "svg"
b) declare module "*.svg" { const src: string; export default src; } in a .d.ts file
c) Set allowJs to true
d) Rename the file to logo.ts
Q12. Which statement about a .d.ts file is correct?
a) It must be imported in every file
b) It can contain function bodies
c) It contains only type declarations and produces no JavaScript output
d) It is compiled into a .js file
Q13. In TypeScript project references, what is required in a referenced project and how is the build run?
a) composite: true in the referenced project, and tsc --build (tsc -b) to build projects in dependency order
b) Nothing special; run tsc
c) strict: false and tsc --watch
d) A webpack config
Q14. Under strict mode, what is the type of e in try { ... } catch (e) { ... }?
a) any
b) Error
c) never
d) unknown
Q15. Why is x.length still an error here?
function f(x: string[] | null) {
if (typeof x === "object") {
x.length;
}
}
a) Arrays are not objects
b) typeof cannot narrow unions
c) typeof null is "object", so x is still string[] | null inside the block
d) length does not exist on arrays
Quick revision notes
- Type predicates (x is T) and assertion functions (asserts x is T) both narrow types.
- Call assertion functions through a name that has an explicit type.
- assertNever checks exhaustiveness at compile time, and it should also throw at runtime.
- Interfaces and namespaces merge. Module augmentation and declare global only work in a module file.
- .d.ts files hold only types. Project references need composite and tsc -b.
Frequently asked questions
When should I use unknown instead of any?
Use unknown for anything you haven't checked yet, like JSON.parse results, API responses and catch variables. It makes you narrow before use. any just switches checking off.
Where does TypeScript look for a package's types?
It looks in the package first (the types field or .d.ts files shipped with it), then in the matching @types package from DefinitelyTyped.
Should I write my own .d.ts for an untyped library?
Yes. Start with a small declare module file that covers only the functions you use, and add more as you need them.
Comments
Post a Comment