I had the same question just now, and still not able to rapidly google up the answer, I come up with this option:
function foo<Enabled=false,T=unknown>(arg: Enabled extends false ? never : T) {
// Implementation.
}
This way foo("value") fails (with default generic arguments arg type evaluates never, thus forbids any assigment to it); foo<1>("value") works (with any value, but false, passed into the first generic argument, T is auto-resolved based on the type of given arg value); and also one can do foo<1,string>("value") to force-check whatever type of arg which is needed.
Perhaps, a better variant:
function foo<
Enabled extends 1 | 0 = 0,
T = never,
>(arg: Enabled extends 0 ? never : T) {
// Implementation.
}
This way:
- First generic argument is restricted to
1 or 0, thus if ones forget that the first generic argument is just a switch, not the target arg type, it will be immeditely clear, as foo<string>('value') fails.
- When
T defaults never, this will also fail: foo<1>('value') — even with the function "enabled" by the first generic argument, the arg inference does not happen, forcing to specify its expected type via the second generic argument, i.e. foo<1, string>('value').