All quizzesHard
Type-Level Generics — Series 2
Preview — 3 of 10 questions
javascript
type UserId = string & { readonly __brand: 'UserId' };
type PostId = string & { readonly __brand: 'PostId' };
function createUserId(id: string): UserId { return id as UserId; }
function getUser(id: UserId) { /* ... */ }
const uid = createUserId('u1');
const pid = 'p1' as PostId;
getUser(uid);
getUser(pid);AgetUser(uid) compiles fine; getUser(pid) is a compile-time error, because PostId's brand ('PostId') doesn't match the 'UserId' brand getUser requires — even though both types are structurally "just a string" underneath
BBoth calls compile fine — TypeScript is always fully structurally typed, so the extra brand properties are ignored
CBoth calls throw a runtime TypeError
DNeither compiles — intersecting string with an object literal type like { readonly __brand: 'UserId' } is invalid syntax
javascript
function firstElement<const T extends readonly unknown[]>(arr: T): T[0] {
return arr[0];
}
const result = firstElement(['a', 'b', 'c']);Aresult has type string — the const modifier has no effect on generic inference
Bresult has type "a" — the const type-parameter modifier (TS 5.0) tells the compiler to infer the narrowest possible (literal) type for T, instead of widening the array to string[]
CThis is a compile-time error — const cannot be used as a type parameter modifier
Dresult has type readonly ["a", "b", "c"] — the whole tuple, not just its first element
What does the asserts val is string return-type annotation do?
javascript
function assertIsString(val: unknown): asserts val is string {
if (typeof val !== 'string') throw new Error('Not a string');
}
function process(val: unknown) {
assertIsString(val);
return val.toUpperCase();
}AIt has no effect on type narrowing — val is still unknown after the call, so this code shouldn't actually compile
BIt automatically converts val to an actual string value at runtime
CIf assertIsString returns normally (i.e., doesn't throw), TypeScript narrows val to string for the rest of the enclosing scope — so val.toUpperCase() compiles without needing an explicit if type-guard block
DIt only works when the call is placed inside an if statement, not as a standalone statement
Sign up free to play
Answer all 10 questions (7 more), see explanations for every answer, and track your score.