Skip to content

Commit eedc389

Browse files
Better assignability errors when the target is an intersection that gets reduced to 'never'.
1 parent 0d7a75e commit eedc389

File tree

3 files changed

+18
-2
lines changed

3 files changed

+18
-2
lines changed

src/compiler/checker.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4102,7 +4102,9 @@ namespace ts {
41024102
return undefined!; // TODO: GH#18217
41034103
}
41044104

4105-
type = getReducedType(type);
4105+
if (!(context.flags & NodeBuilderFlags.PreserveVacuousIntersections)) {
4106+
type = getReducedType(type);
4107+
}
41064108

41074109
if (type.flags & TypeFlags.Any) {
41084110
context.approximateLength += 3;
@@ -15528,6 +15530,10 @@ namespace ts {
1552815530
return result;
1552915531
}
1553015532
}
15533+
else if (getObjectFlags(originalTarget) & ObjectFlags.IsNeverIntersection) {
15534+
const intersectionString = typeToString(originalTarget, /*enclosingDeclaration*/ undefined, TypeFormatFlags.PreserveVacuousIntersections);
15535+
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.The_type_never_was_reduced_from_the_intersection_0_Each_type_of_that_intersection_has_properties_that_conflict_so_values_of_that_type_can_never_exist, intersectionString);
15536+
}
1553115537
if (!headMessage && maybeSuppress) {
1553215538
lastSkippedInfo = [source, target];
1553315539
// Used by, eg, missing property checking to replace the top-level message with a more informative one
@@ -24098,6 +24104,10 @@ namespace ts {
2409824104
relatedInfo = suggestion.valueDeclaration && createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestedName);
2409924105
}
2410024106
else {
24107+
if (getObjectFlags(containingType) & ObjectFlags.IsNeverIntersection) {
24108+
const intersectionString = typeToString(containingType, /*enclosingDeclaration*/ undefined, TypeFormatFlags.PreserveVacuousIntersections);
24109+
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.The_type_never_was_reduced_from_the_intersection_0_Each_type_of_that_intersection_has_properties_that_conflict_so_values_of_that_type_can_never_exist, intersectionString);
24110+
}
2410124111
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(containingType));
2410224112
}
2410324113
}

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5653,5 +5653,9 @@
56535653
"An optional chain cannot contain private identifiers.": {
56545654
"category": "Error",
56555655
"code": 18030
5656+
},
5657+
"The type 'never' was reduced from the intersection '{0}'. Each type of that intersection has properties that conflict, so values of that type can never exist.": {
5658+
"category": "Error",
5659+
"code": 18031
56565660
}
56575661
}

src/compiler/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3687,6 +3687,7 @@ namespace ts {
36873687
OmitParameterModifiers = 1 << 13, // Omit modifiers on parameters
36883688
UseAliasDefinedOutsideCurrentScope = 1 << 14, // Allow non-visible aliases
36893689
UseSingleQuotesForStringLiteralType = 1 << 28, // Use single quotes for string literal type
3690+
PreserveVacuousIntersections = 1 << 29, // uh oh...
36903691

36913692
// Error handling
36923693
AllowThisInObjectLiteral = 1 << 15,
@@ -3730,6 +3731,7 @@ namespace ts {
37303731

37313732
UseAliasDefinedOutsideCurrentScope = 1 << 14, // For a `type T = ... ` defined in a different file, write `T` instead of its value, even though `T` can't be accessed in the current scope.
37323733
UseSingleQuotesForStringLiteralType = 1 << 28, // Use single quotes for string literal type
3734+
PreserveVacuousIntersections = 1 << 29, // uh oh
37333735

37343736
// Error Handling
37353737
AllowUniqueESSymbolType = 1 << 20, // This is bit 20 to align with the same bit in `NodeBuilderFlags`
@@ -3749,7 +3751,7 @@ namespace ts {
37493751
NodeBuilderFlagsMask = NoTruncation | WriteArrayAsGenericType | UseStructuralFallback | WriteTypeArgumentsOfSignature |
37503752
UseFullyQualifiedType | SuppressAnyReturnType | MultilineObjectLiterals | WriteClassExpressionAsTypeLiteral |
37513753
UseTypeOfFunction | OmitParameterModifiers | UseAliasDefinedOutsideCurrentScope | AllowUniqueESSymbolType | InTypeAlias |
3752-
UseSingleQuotesForStringLiteralType,
3754+
UseSingleQuotesForStringLiteralType | PreserveVacuousIntersections,
37533755
}
37543756

37553757
export const enum SymbolFormatFlags {

0 commit comments

Comments
 (0)