Both are tools for steering inference of a type parameter.
const type parameters (TS 5.0). By default an object or array literal argument widens ({ role: "admin" } infers { role: string }), so API authors told callers to write as const. A const modifier on the type parameter (function f<const T>(x: T)) makes the literal expressions in the argument get the most precise type, like as const: literals, readonly properties, readonly tuples.
Rules from the PR and release notes:
- Allowed on type parameters of functions, methods and classes; an error on interfaces and type aliases (TS1277).
- It only affects literals written directly in the call. A variable argument is untouched:
names(list)staysstring[]. - If the constraint is a mutable array type (
T extends string[]), the readonly tuple candidate fails the constraint. The 5.0 notes say inference falls back tostring[], so writereadonly string[]. Version note: in my runs 5.0.4 gavestring[]for that mutable case but 5.9.3 and 7.0.2 gave["a", "b"], so behaviour changed after 5.0; thereadonlyconstraint gives the same precise result everywhere and is the portable form.
NoInfer<T> (TS 5.4). Wrapping a type in NoInfer blocks inference to that position; it is otherwise identical to T (the PR says the two are the same type outside inference). In light<C extends string>(colors: C[], fallback?: C) a stray "blue" becomes another candidate and widens C, so the call is accepted. With fallback?: NoInfer<C>, only colors supplies candidates and "blue" is checked against them and rejected.
The alternative before 5.4 was a second type parameter D extends C, which the notes call a smell: a parameter used once.