Challenge 2: Write an isOneOf Guard — Possible Solution ==================================================================== function isOneOf( value: unknown, options: T ): value is T[number] { return options.includes(value); } // --- Usage --- const ROLES = ["admin", "member", "guest"] as const; type Role = (typeof ROLES)[number]; // "admin" | "member" | "guest" function setRole(value: unknown): Role { if (isOneOf(value, ROLES)) { // value is narrowed to "admin" | "member" | "guest" here return value; } throw new Error(`Invalid role: ${String(value)}`); } setRole("admin"); // ✅ returns "admin", typed as Role setRole("member"); // ✅ returns "member" // setRole("owner"); // compiles fine at the call site (value: unknown), // but throws at runtime — exactly the point: the // guard is what actually enforces the restriction. // Works for numbers too, not just strings: const HTTP_SUCCESS_CODES = [200, 201, 204] as const; function isSuccessStatus(code: unknown): code is (typeof HTTP_SUCCESS_CODES)[number] { return isOneOf(code, HTTP_SUCCESS_CODES); } if (isSuccessStatus(201)) { console.log("Success!"); // code narrowed to 200 | 201 | 204 } WHY THIS WORKS -------------- - `T extends readonly unknown[]` accepts a `readonly` tuple/array — using `as const` on the options array (like ROLES above) is what turns it into a tuple of specific literal types instead of a widened `string[]`, which is exactly what makes `T[number]` resolve to the literal union `"admin" | "member" | "guest"` rather than plain `string`. - `T[number]` is TypeScript's way of indexing a tuple/array type by its element type — it produces the union of every element in the tuple, which is the exact type the guard should narrow `value` to on success. - `options.includes(value)` does the actual runtime check — this is the part that makes the guard trustworthy rather than a "lying" guard like the one warned about in this chapter's gotcha: the predicate's return type is backed by a real comparison against the actual allowed values.