Type-Level Programming — Series 2

Preview — 3 of 10 questions

javascript
type Email = string & { readonly __brand: 'Email' };
function createEmail(input: string): Email | null {
  return input.includes('@') ? (input as Email) : null;
}
function sendTo(email: Email) { /* ... */ }
const maybeEmail = createEmail('a@b.com');
if (maybeEmail) {
  sendTo(maybeEmail);
}
sendTo('raw@string.com');
AsendTo(maybeEmail) compiles fine, since narrowing inside the if block rules out null, leaving a genuine Email; sendTo('raw@string.com') is a compile-time error, because a bare string literal — lacking the __brand marker — isn't assignable to Email, no matter how "email-shaped" it looks
BBoth calls to sendTo compile fine
CBoth calls are compile-time errors
DsendTo('raw@string.com') compiles fine, because string literals are always assignable to any branded type based on string

javascript
type Split<S extends string, D extends string> = S extends `${infer Head}${D}${infer Tail}`
  ? [Head, ...Split<Tail, D>]
  : [S];
type Parts = Split<'a,b,c', ','>;
AParts is string[]
BCompile-time error — this pattern is limited to a fixed maximum recursion depth of 3
CParts is the tuple ['a', 'b', 'c'] — the recursive conditional type repeatedly splits off everything before the next delimiter, prepending it to the result of recursively splitting the remainder, until no delimiter is left
DParts is the original literal 'a,b,c', unchanged

javascript
class Animal {}
class Dog extends Animal { bark() { return 'Woof'; } }
class Cat extends Animal {}

function addCat(animals: Animal[]) {
  animals.push(new Cat());
}
const dogs: Dog[] = [new Dog()];
addCat(dogs);
dogs[1].bark();
ACompile-time error on addCat(dogs) — TypeScript's array typing is fully sound and would never permit this
BRuntime error occurs immediately on the addCat(dogs) call itself
CCompiles fine at every line, and dogs[1].bark() returns 'Woof' regardless, since JavaScript doesn't enforce array element types at runtime
DCompiles fine at every line — TypeScript treats arrays covariantly (Dog[] is assignable to Animal[]), which is a known, deliberately-accepted unsound spot in the type system; addCat can push a Cat into what's actually the underlying Dog[] array, so dogs[1].bark() type-checks but throws a runtime TypeError, since dogs[1] is genuinely a Cat with no bark method

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.