Closed as not planned
Closed as not planned
Description
🔎 Search Terms
"type guard union types narrowing"
"asserts is not refining type"
"type refinement union types bug"
"dryRun outputPath assertion"
"optional property refinement bug"
🕗 Version & Regression Information
This changed between versions 4.7.4 and 4.8.4.
After bisecting i found that the regression has been introduced in commit: 2c68ded95498dc637acdb00e8349f51832f5a6df.
⏯ Playground Link
💻 Code
export interface FilesCleanupCliFlags {
readonly dryRun?: boolean;
readonly outputPath?: string;
}
// Type guard with `is` for refining union types
function checkCliFlags(
flags: FilesCleanupCliFlags,
): flags is { readonly dryRun: true; readonly outputPath: string } | { readonly dryRun?: false } {
if (flags.dryRun && !flags.outputPath) {
throw new Error('The --outputPath option is required in dry-run mode and must specify the full file path.');
}
return true;
}
// Main function using the type guard
function main() {
const options: FilesCleanupCliFlags = {};
if (checkCliFlags(options)) {
const { dryRun, outputPath } = options;
// Expected: TypeScript should refine `options` to { dryRun: true; outputPath: string } | { dryRun?: false }
// Actual: TypeScript refines `options` only to { dryRun: true; outputPath: string },
// omitting `{ dryRun?: false }` case.
}
}
// Using `asserts is` version of the check
function checkCliFlagsWithAsserts(
flags: FilesCleanupCliFlags,
): asserts flags is { readonly dryRun: true; readonly outputPath: string } | { readonly dryRun?: false } {
if (flags.dryRun && !flags.outputPath) {
throw new Error('The --outputPath option is required in dry-run mode and must specify the full file path.');
}
}
// Main function using asserts
function mainWithAsserts() {
const options: FilesCleanupCliFlags = {};
checkCliFlagsWithAsserts(options);
const { dryRun, outputPath } = options;
// Expected: TypeScript should refine `options` to { dryRun: true; outputPath: string } | { dryRun?: false }
// Actual: TypeScript refines `options` only to { dryRun: true; outputPath: string },
// omitting `{ dryRun?: false }` case.
}
🙁 Actual behavior
TypeScript does not refine the type of options
correctly after the type guard (checkCliFlags
) or assertion (checkCliFlagsWithAsserts
)
- When using
checkCliFlags(optins)
orcheckCliFlagsWithAsserts(options)
, the expected refinement is:{ readonly dryRun: true; readonly outputPath: string } | { readonly dryRun?: false }
- However, TypeScript only refines
options
to{ readonly dryRun: true; readonly outputPath: string }
, and the{ dryRun?: false }
branch is omitted.
🙂 Expected behavior
TypeScript should refine the type of options
to:
{ readonly dryRun: true; readonly outputPath: string } | { readonly dryRun?: false }
Additional information about the issue
No response