The NoInfer utility type

Changes in new versions / TypeScript 5.4

// *** before: ***
function createLogger<T>(defaultLevel: T, levels: T[]): T {
    return defaultLevel;
}
// T is inferred from defaultLevel and from levels alike, so a stray
// element in levels quietly widens T to the whole list
createLogger("info", ["info", "debug", "typo"]); // T widened, and no error

// *** in version 5.4: ***
function createLoggerChecked<T>(defaultLevel: T, levels: NoInfer<T>[]): T {
    return defaultLevel;
}
createLoggerChecked("info", ["info", "debug", "typo"]);
// <-Error: T is inferred from defaultLevel ("info") only,
// so "debug" and "typo" are not part of T = "info"