π Search Terms
"never type guard", "never returning function does not guard", "type guard parameter"
π Version & Regression Information
Tested in the playground on major versions 4.0.5 to 6.0.3, same for all.
β― Playground Link
https://www.typescriptlang.org/play/?ts=6.0.3#code/GYVwdgxgLglg9mABAcwKZQOIgIYCcAmAPACoB8AFMGAFyLkBG2MANreQJSIC8piYqAN1S5OPRMXa1iiAN4AoRIlzoQuJFXIduvGYigALXHADuiAXBj5EABgDciAL7tbch3LmhIsBIhgBbAAdmGAgYKHIBbFZZPWxkWgBybAT7bFoAZyhcGDBkR0QAHxioOMT6BIAaRHpaMBA-emFHTnlFZShVJDRMHAJNRhZRHQVFX2A6SOYAOhK8ri5EJITOAeYOFxG2lTUzKKn6ewB6Q8RwVAAPANRoVCthI1wRp1d3T2h4JAugkLCIqNpdLNEslUhksjk8g5CsVSotylUanx6o1cM1ZCN2p0UOgsHh8P0mNEtGJ+EIRNp0aMxhM9rNuAslitCet3FTMTtJvsjic4ABrJ7sF5yCAITK7aKA2FLUGITLZXL5IqS+JwyrVWrIppQhbKspqxEAFkcwtFUEQ2G4vkCwVC4UmzkQx3NYAAniawGL6JavjbfvbuUiGsIgA
π» Code
A parameter explicitly typed as () => never can be used as a type guard, but one with an implicit type () => void does not.
function getGuard<T>(fn: (bail: () => never) => T): T {
return fn(() => { throw void 0; });
}
function implicit(val: { tag: 'a'; a: string } | { tag: 'b', b: number }) {
return getGuard((bail) => {
if (val.tag == 'a') bail();
return val.b; // unexpected error
})
}
function explicit(val: { tag: 'a'; a: string } | { tag: 'b', b: number }) {
return getGuard((bail: () => never) => {
if (val.tag == 'a') bail();
return val.b; // ok
})
}
const val: { tag: 'a'; a: string } | { tag: 'b', b: number } = { tag: 'b', b: 4 }
const a = implicit(val); // any
const b = explicit(val); // number
π Actual behavior
The type is not narrowed after invoking a never-returning function in an if block
π Expected behavior
The type is narrowed the same way that it does for an explicitly typed guard, a throw, or a return etc..
Additional information about the issue
No response
π Search Terms
"never type guard", "never returning function does not guard", "type guard parameter"
π Version & Regression Information
Tested in the playground on major versions 4.0.5 to 6.0.3, same for all.
β― Playground Link
https://www.typescriptlang.org/play/?ts=6.0.3#code/GYVwdgxgLglg9mABAcwKZQOIgIYCcAmAPACoB8AFMGAFyLkBG2MANreQJSIC8piYqAN1S5OPRMXa1iiAN4AoRIlzoQuJFXIduvGYigALXHADuiAXBj5EABgDciAL7tbch3LmhIsBIhgBbAAdmGAgYKHIBbFZZPWxkWgBybAT7bFoAZyhcGDBkR0QAHxioOMT6BIAaRHpaMBA-emFHTnlFZShVJDRMHAJNRhZRHQVFX2A6SOYAOhK8ri5EJITOAeYOFxG2lTUzKKn6ewB6Q8RwVAAPANRoVCthI1wRp1d3T2h4JAugkLCIqNpdLNEslUhksjk8g5CsVSotylUanx6o1cM1ZCN2p0UOgsHh8P0mNEtGJ+EIRNp0aMxhM9rNuAslitCet3FTMTtJvsjic4ABrJ7sF5yCAITK7aKA2FLUGITLZXL5IqS+JwyrVWrIppQhbKspqxEAFkcwtFUEQ2G4vkCwVC4UmzkQx3NYAAniawGL6JavjbfvbuUiGsIgA
π» Code
A parameter explicitly typed as
() => nevercan be used as a type guard, but one with an implicit type() => voiddoes not.π Actual behavior
The type is not narrowed after invoking a never-returning function in an if block
π Expected behavior
The type is narrowed the same way that it does for an explicitly typed guard, a throw, or a return etc..
Additional information about the issue
No response