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')
.