TSConfig: noUncheckedIndexedAccess
1 card- 01
const users: string[] = []; const firstUser = users[0]; firstUser.toUpperCase();With
strict: trueand nothing else, does this compile?- A
Yes, because
firstUseris aconstand cannot beundefined - B
No:
users[0]isstring | undefinedunderstrict - C
No: reading index
0of an empty array literal is a constant error - D
Yes:
users[0]is typedstring, and only the separatenoUncheckedIndexedAccessflag addsundefinedto indexed reads
- A
Everyday Types
4 cards- 02
declare function request(url: string, method: "GET" | "POST"): void; const method = "GET"; let m = method; request("/users", m);Does the call compile under
strict?- A
Yes:
mis initialised from a"GET"literal, so it keeps that literal type - B
No:
mis declared withlet, so its type widens tostring, which is not assignable to"GET" | "POST" - C
Yes, but only because
"GET"andstringare the same type at runtime - D
No: string literal types can only be used with
constdeclarations, solet mis itself an error
- A
- 03
declare function request(url: string, method: "GET" | "POST"): void; const req = { url: "/users", method: "GET" }; request(req.url, req.method);This does not compile. Which single change fixes it without adding a type annotation?
- A
Add
as constafter the object literal somethodis typed"GET"rather thanstring - B
Replace
const reqwithlet req, sinceletallows narrower property types - C
Wrap the call as
request(req.url, req.method!)to assert the value is present - D
Write
method: "GET" as stringso the property has an explicit type
- A
- 04
Which of these lines is a compile error?
const a = "hello" as unknown as number; // 1 const b = "hello" as number; // 2 const c = document.getElementById("x") as HTMLCanvasElement; // 3- A
None: type assertions are never checked, they only silence the compiler
- B
Line 3:
getElementByIdreturnsHTMLElement | null, which cannot be asserted to a subtype - C
Line 1: a value cannot be asserted twice in one expression
- D
Line 2:
stringandnumberdo not sufficiently overlap, so the assertion is rejected
- A
- 05
function handle(value: unknown) { value.toFixed(2); // A const n = value as number; // B if (typeof value === "string") value.toUpperCase(); // C }Which statements compile?
- A
B and C: an assertion or a
typeofcheck is needed before any member access - B
A, B and C:
unknownbehaves likeanyinside a function body - C
Only C:
unknownpermits nothing until it is narrowed - D
Only B:
typeofnarrowing does not apply tounknown
- A
Narrowing
6 cards- 06
function firstOf(list: string[] | null | string) { if (typeof list === "object") { return list[0]; } }What does the compiler say about
list[0]?- A
Error:
typeofcannot narrow a union that contains an array type - B
Nothing:
typeof list === "object"narrowslisttostring[] - C
Error:
listis possiblynull, becausetypeof nullis"object"and TypeScript knows it - D
Nothing, but
list[0]is typedstring | nullinstead ofstring
- A
- 07
function label(count: number | undefined) { if (count) { return `${count} items`; } return "none"; }The types are correct and it compiles. What is wrong?
- A
countinside the block is stillnumber | undefined, so the template literal is unsafe - B
Nothing: truthiness is the recommended way to narrow away
undefined - C
label(0)returns"none", because0is falsy and the check narrows away more thanundefined - D
The function's return type is
string | undefined, because one branch is unguarded
- A
- 08
type Shape = { kind: "circle"; r: number } | { kind: "square"; side: number }; function area(s: Shape): number { switch (s.kind) { case "circle": return Math.PI * s.r ** 2; case "square": return s.side ** 2; default: { const unreachable: never = s; return unreachable; } } }A teammate adds
{ kind: "triangle"; base: number; height: number }toShapeand nothing else. What happens?- A
A compile error at the
switch, because aswitchon a union must be exhaustive - B
A compile error on the
Shapedeclaration, because members must be added to everyswitchfirst - C
A compile error at
const unreachable: never = s, becausesis now the triangle type there - D
Nothing until runtime, where
areareturnsundefinedfor a triangle
- A
- 09
function same(x: string | number, y: string | boolean) { if (x === y) { x; y; } }Inside the
if, what are the types ofxandy?- A
Both are
string: strict equality can only hold when both sides share a type - B
xisstring | numberandyisstring | boolean:===does not narrow - C
xisstring | numberandyisstring: only the right-hand side narrows - D
Both are
string | number | boolean: the union of everything either could be
- A
- 10
function isFish(pet: Fish | Bird): pet is Fish { return "fly" in pet; // wrong: this is true for a Bird } if (isFish(pet)) pet.swim();What does the compiler report?
- A
An error:
inchecks cannot be used in a function with a type predicate - B
A warning that
"fly" in petnarrows toBird, contradicting the return type - C
Nothing: a type predicate is trusted as written, and the bug surfaces only at runtime
- D
An error: the predicate
pet is Fishdoes not match what the function body checks
- A
- 11
function reset(box: { value: string | null }) { box.value = null; } function use(box: { value: string | null }) { if (box.value !== null) { reset(box); return box.value.length; } }Does this compile, and is it safe?
- A
It compiles but throws at runtime: narrowing survives the call, though
resetset the value tonull - B
It does not compile: property paths like
box.valueare never narrowed, only local variables are - C
It compiles and is safe:
resetreceives a copy, sobox.valuecannot change - D
It does not compile: a function call invalidates the narrowing of
box.value
- A
More on Functions
4 cards- 12
type Callback = () => void; const a: Callback = () => 42; // 1 function b(): void { return 42; } // 2 const c: Callback = function () { return "done"; }; // 3Which lines are errors?
- A
Lines 1 and 3: arrow and function expressions are checked more strictly than declarations
- B
Only line 2: a
voidreturn type in a function type is contextual and ignores what is returned, while a literalvoiddeclaration forbids returning a value - C
None:
voidmeans the return value is discarded, so any value is allowed everywhere - D
Lines 1, 2 and 3: a
voidfunction may not return a value
- A
- 13
function len(s: string): number; function len(arr: any[]): number; function len(x: any) { return x.length; } len(Math.random() > 0.5 ? "hello" : [0]);What happens?
- A
It compiles: the implementation signature accepts
any, so a union argument is fine - B
It compiles: the compiler tries each overload and unions their return types
- C
Error: no overload matches
string | number[], because each call must pick one overload signature - D
Error: overloads must have a shared return type, and these do not
- A
- 14
function minimumLength<T extends { length: number }>(obj: T, min: number): T { if (obj.length >= min) return obj; return { length: min }; }Why is the second
returnan error?- A
The function needs an explicit type argument at each call before
Tcan be returned - B
{ length: min }satisfies the constraint but is notT:Tcould be a narrower type such asstring, and callers get back whateverTwas - C
lengthis a read-only property of the constraint, so it cannot be assigned in a literal - D
An object literal cannot be returned from a generic function
- A
- 15
const args = [8, 5]; const angle = Math.atan2(...args);Why does this fail to compile?
- A
Spread syntax is only allowed with rest parameters, and
atan2declares two named parameters - B
argsis inferred asnumber[], whose length is unknown, so spreading it does not prove two arguments are passed - C
Math.atan2expects a tuple, and arrays are never assignable to tuples - D
Array literals are read-only by default and cannot be spread into a call
- A
Object Types
4 cards- 16
interface Person { name: string; age: number } interface ReadonlyPerson { readonly name: string; readonly age: number } const writable: Person = { name: "Ann", age: 40 }; const frozen: ReadonlyPerson = writable; writable.age++; console.log(frozen.age);What is the result?
- A
Runtime error: objects typed
readonlyare frozen withObject.freeze - B
Compile error: a
Personis not assignable toReadonlyPersonbecause the properties differ in mutability - C
It compiles and prints 41:
readonlyonly stops writes throughfrozen, and assignability ignores the modifier - D
It compiles and prints 40: assigning to a
readonlytype copies the object
- A
- 17
interface Options { color?: string; width?: number } declare function paint(o: Options): void; const opts = { colour: "red", width: 10 }; paint(opts); // 1 paint({ colour: "red", width: 10 }); // 2Which call is an error?
- A
Both:
colouris not a property ofOptions - B
Neither: all properties of
Optionsare optional, so any object qualifies - C
Only call 2: excess property checking applies to object literals passed directly, not to a variable that happens to have extra properties
- D
Only call 1: a variable's inferred type must match
Optionsexactly, while a literal is contextually typed
- A
- 18
interface Scores { [subject: string]: number; average: number; name: string; }What does the compiler say?
- A
Nothing: named properties are checked separately from the index signature
- B
Error on
name: every property must be assignable to the string index signature's type, andstringis notnumber - C
Error: an interface may not mix an index signature with named properties
- D
Error on
average: a property may not have the same type as the index signature
- A
- 19
interface A { x: string } interface B { x: number } type C = A & B; // 1 interface D extends A, B {} // 2Which declaration is an error?
- A
Both:
xhas conflicting types inAandB - B
Neither: in both,
xbecomesstring | number - C
Only declaration 1: intersections require every property to agree, while
extendstakes the last one - D
Only declaration 2:
extendsrequires compatible members, while an intersection silently givesxthe typenever
- A
Generics
1 card- 20
function first<T>(items: T[]): T { return items[0]; } const x = first([]);What is the type of
xunderstrict?- A
undefined - B
unknown - C
any - D
never
- A
Keyof Type Operator
1 card- 21
type A = keyof { [n: number]: unknown }; type B = keyof { [s: string]: unknown };What are
AandB?- A
Both are
string: object keys are always strings in JavaScript - B
Aisnumber,Bisstring | number - C
Both are
string | number | symbol - D
Aisnumber,Bisstring
- A
Typeof Type Operator
1 card- 22
function makeId() { return { id: 1, at: new Date() }; } type Id = typeof makeId();What does the compiler say?
- A
Idis() => { id: number; at: Date } - B
Idis{ id: number; at: Date } - C
Error: functions with inferred return types cannot be used with
typeof - D
Error:
typeofin a type position accepts an identifier or property path, not a call expression; useReturnType<typeof makeId>
- A
Indexed Access Types
1 card- 23
type Person = { name: string; age: number; alive: boolean }; const key = "age"; type Age = Person[key];What is wrong?
- A
keyis a value, and only types may be used in an indexed access; writePerson[typeof key]or use the literal"age"directly - B
Nothing:
Ageisnumber - C
Person[key]needskeydeclared withlet, sinceconstvalues are not visible to the type system - D
Indexed access only accepts unions, so
Person["age"]is the only valid form here
- A
Conditional Types
3 cards- 24
type ToArray<T> = T extends any ? T[] : never; type ToArrayNonDist<T> = [T] extends [any] ? T[] : never; type A = ToArray<string | number>; type B = ToArrayNonDist<string | number>;What are
AandB?- A
Both are
(string | number)[] - B
Aisstring[] | number[],Bis(string | number)[] - C
Ais(string | number)[],Bisstring[] | number[] - D
Both are
string[] | number[]
- A
- 25
type IsString<T> = T extends string ? true : false; type R = IsString<never>;What is
R?- A
false - B
boolean - C
true - D
never
- A
- 26
declare function parse(input: string): number; declare function parse(input: number): string; type R = ReturnType<typeof parse>;What is
R?- A
number | string - B
string: inference uses the last overload - C
Error:
ReturnTypecannot be applied to an overloaded function - D
number: inference uses the first overload
- A
Mapped Types
2 cards- 27
type Loose = { readonly id?: string; readonly name?: string }; type Tightened = { [K in keyof Loose]-?: Loose[K] };What is
Tightened?- A
{ id: string; name: string }: mapping over keys produces plain properties - B
{ readonly id: string; readonly name: string }:-?removes optionality, andreadonlyis preserved because the mapping is homomorphic - C
{ readonly id?: string; readonly name?: string }:-?only applies to mapped types overstring - D
{ id: string | undefined; name: string | undefined }: removing?keepsundefinedin the type
- A
- 28
type Circle = { kind: "circle"; radius: number }; type Fields = { [K in keyof Circle as Exclude<K, "kind">]: Circle[K] };What is
Fields?- A
{ radius: number; kind?: "circle" }: excluded keys become optional - B
{ kind: never; radius: number }: the excluded key remains with typenever - C
{ radius: number }: remapping a key toneverdrops the property - D
Error: the
asclause must produce astringtype for every key
- A
Template Literal Types
1 card- 29
type Axis = "x" | "y"; type Bound = "min" | "max"; type Key = `${Bound}${Capitalize<Axis>}`;What is
Key?- A
`${string}${string}` - B
"minX" | "maxY" - C
"minX" | "minY" | "maxX" | "maxY" - D
"minx" | "maxy"
- A
Classes
4 cards- 30
class Cat { private name = "cat"; } class Dog { private name = "dog"; } const pet: Cat = new Dog();Why is the assignment rejected, even though the shapes match?
- A
Types with
private(orprotected) members are only compatible when the member comes from the same declaration, so two classes each declaring their ownprivate nameare not interchangeable - B
Classes are always nominal in TypeScript, so no two distinct classes are ever assignable
- C
privatemembers are erased, soCatandDogare both{}and{}is not assignable to a class - D
Property initialisers make the members
readonly, and readonly properties block assignment between classes
- A
- 31
interface Checkable { check(name: string): boolean } class NameChecker implements Checkable { check(s) { return s.toLowerCase() === "ok"; } }Under
strict, what happens?- A
It compiles, and
sisstringbecause of contextual typing from the interface - B
It compiles:
implementsgives the method its parameter types from the interface - C
Error: a method implementing an interface must repeat the interface's return type
- D
Error:
simplicitly has ananytype, becauseimplementsonly checks the class afterwards and does not type its members
- A
- 32
class Base { name = "base"; constructor() { console.log("My name is " + this.name); } } class Derived extends Base { name = "derived"; } new Derived();What is printed?
- A
My name is base - B
A compile error:
namemay not be redeclared in a subclass - C
My name is derived - D
My name is undefined
- A
- 33
class Counter { count = 0; increment() { this.count++; } } const c = new Counter(); const tick = c.increment; tick();What do the compiler and the runtime do?
- A
Compile error: a method cannot be passed as a callback without
bind - B
Compile error under
noImplicitThis, becausethisinsideincrementis untyped - C
It compiles and works: methods keep their
thiswhen detached from the instance - D
It compiles, and at runtime
thisisundefinedinsideincrement, sothis.count++throws a TypeError
- A
Type Compatibility
2 cards- 34
let one = (a: number) => 0; let two = (a: number, s: string) => 0; two = one; // 1 one = two; // 2Which assignment is an error?
- A
Assignment 1:
onetakes fewer parameters thantwodeclares - B
Neither: parameter count is not part of a function's type
- C
Both: function types must have identical parameter lists
- D
Assignment 2:
tworequires a second argument that callers ofonewill never pass
- A
- 35
type User = { id: number; name: string }; const u: User = { id: 1, name: "Ann" }; for (const k of Object.keys(u)) { u[k]; }Why is
u[k]an error understrict, and is it a compiler mistake?- A
It is a mistake:
Object.keysshould return(keyof User)[]and the definition is simply out of date - B
for...ofcannot iterate an array of literal types, sokwidens tostring - C
Indexing an object with a variable key is always an error unless the object has an index signature
- D
Object.keysreturnsstring[]deliberately: a value of typeUsermay have extra properties at runtime, so its keys are not known to be only"id" | "name"
- A
Utility Types
2 cards- 36
type User = { id: number; name: string }; type A = Pick<User, "nickname">; type B = Omit<User, "nickname">;What does the compiler say?
- A
Ais an error,Bcompiles asUserunchanged:Pickconstrains its keys tokeyof T,Omitaccepts any string - B
Both are errors:
"nickname"is not a key ofUser - C
Both compile: neither utility checks its keys against
T - D
Bis an error,Acompiles as{}
- A
- 37
type Config = Readonly<{ name: string; tags: string[] }>; declare const cfg: Config; cfg.name = "x"; // 1 cfg.tags.push("x"); // 2Which line is an error?
- A
Only line 2: arrays inside a
Readonlyobject becomereadonly string[] - B
Both:
Readonlyfreezes the whole value - C
Only line 1:
Readonlymakes the properties of one level read-only, andtagsis still a mutablestring[] - D
Neither:
Readonlyis a documentation hint with no effect on assignments
- A
Enums
2 cards- 38
enum Direction { Up = "UP", Down = "DOWN" } declare function move(d: Direction): void; move("UP"); move(Direction.Up);What happens to
move("UP")?- A
Error:
"UP"is not assignable toDirection; string enum members are distinct types that only the enum's own members satisfy - B
It compiles: a string enum member is just its string value
- C
Error: string enums cannot be used as parameter types
- D
It compiles, but only if the enum is declared
const enum
- A
- 39
const enum Level { Low, High } const names = Object.keys(Level);Why is this an error?
- A
const enummembers are read-only, so reflecting over them is disallowed - B
A
const enumis fully inlined at each use and emits no runtime object, so there is nothing to reference as a value - C
Levelhas no string values, andObject.keysrequires a string enum - D
Object.keysdoes not accept enums of any kind
- A
TSConfig: exactOptionalPropertyTypes
1 card- 40
interface Settings { theme?: "dark" | "light" } const s: Settings = { theme: undefined };When is this an error?
- A
Only with
exactOptionalPropertyTypesenabled, which distinguishes an absent property from one explicitly set toundefined - B
Never: an optional property always accepts
undefined - C
Always under
strict, becauseundefinedis not a member of the union - D
Only without
strictNullChecks, whenundefinedis not part of any type
- A
TSConfig: useUnknownInCatchVariables
1 card- 41
try { risky(); } catch (e) { console.log(e.message); }Under
strict, why ise.messagean error?- A
eisunknownunderstrict, because anything can be thrown; narrow withinstanceof Errorbefore reading properties - B
eisError, andmessageis a protected property - C
It is not an error:
eisanyin every configuration - D
catchvariables arenever, since exceptions are not part of the type system
- A
TSConfig: strictFunctionTypes
1 card- 42
interface ViaMethod { handle(x: string | number): void } interface ViaProperty { handle: (x: string | number) => void } const a: ViaMethod = { handle(x: string) {} }; const b: ViaProperty = { handle: (x: string) => {} };Under
strict, which assignment is rejected?- A
Both: a handler for
stringcannot acceptstring | number - B
Only
b:strictFunctionTypeschecks function-typed properties contravariantly, while method syntax is deliberately left bivariant - C
Only
a: method declarations are checked more strictly than arrow functions - D
Neither: parameter types are compared bivariantly in every position
- A
TypeScript 4.9 Release Notes: satisfies
1 card- 43
type RGB = [number, number, number]; type Palette = Record<"red" | "green", string | RGB>; const annotated: Palette = { red: [255, 0, 0], green: "#00ff00" }; const satisfied = { red: [255, 0, 0], green: "#00ff00" } satisfies Palette; annotated.green.toUpperCase(); // 1 satisfied.green.toUpperCase(); // 2Which line compiles?
- A
Both:
satisfiesand a type annotation are two spellings of the same check - B
Neither:
greenisstring | RGBin both, andRGBhas notoUpperCase - C
Only line 2:
satisfiesvalidates the literal againstPalettebut keeps the inferred type, sogreenis known to be astring - D
Only line 1:
satisfieswidens each property to the checked type
- A
Declaration Merging
1 card- 44
interface Box { height: number } interface Box { width: number } type Size = { height: number }; type Size = { width: number };What does the compiler say?
- A
Both pairs are errors: a name may only be declared once
- B
The interfaces merge into
{ height: number; width: number }; the secondtype Sizeis a duplicate identifier error - C
Both pairs merge: interfaces and type aliases with the same name combine their members
- D
The type aliases merge; the second
interface Boxis an error because interfaces are closed
- A
Modules: Theory
1 card- 45
Two files in a project, each with no
importorexportstatement:// a.ts const config = { debug: true }; // b.ts const config = { debug: false };What happens?
- A
Error
Cannot redeclare block-scoped variable 'config': a file with no import or export is a script, and every script shares one global scope - B
Nothing: each file is its own module, so the two
configvariables are unrelated - C
b.tswins: later files shadow earlier ones in compilation order - D
Error only if
isolatedModulesis on; otherwise the files are compiled separately
- A
End of deck · 45 cards