Better assignability errors when the target is an intersection that gets reduced to 'never'.

This commit is contained in:
Daniel Rosenwasser
2020-03-26 02:37:51 -07:00
parent 0d7a75edbb
commit eedc389c74
3 changed files with 18 additions and 2 deletions
+11 -1
View File
@@ -4102,7 +4102,9 @@ namespace ts {
return undefined!; // TODO: GH#18217
}
type = getReducedType(type);
if (!(context.flags & NodeBuilderFlags.PreserveVacuousIntersections)) {
type = getReducedType(type);
}
if (type.flags & TypeFlags.Any) {
context.approximateLength += 3;
@@ -15528,6 +15530,10 @@ namespace ts {
return result;
}
}
else if (getObjectFlags(originalTarget) & ObjectFlags.IsNeverIntersection) {
const intersectionString = typeToString(originalTarget, /*enclosingDeclaration*/ undefined, TypeFormatFlags.PreserveVacuousIntersections);
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);
}
if (!headMessage && maybeSuppress) {
lastSkippedInfo = [source, target];
// Used by, eg, missing property checking to replace the top-level message with a more informative one
@@ -24098,6 +24104,10 @@ namespace ts {
relatedInfo = suggestion.valueDeclaration && createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestedName);
}
else {
if (getObjectFlags(containingType) & ObjectFlags.IsNeverIntersection) {
const intersectionString = typeToString(containingType, /*enclosingDeclaration*/ undefined, TypeFormatFlags.PreserveVacuousIntersections);
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);
}
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(containingType));
}
}
+4
View File
@@ -5653,5 +5653,9 @@
"An optional chain cannot contain private identifiers.": {
"category": "Error",
"code": 18030
},
"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.": {
"category": "Error",
"code": 18031
}
}
+3 -1
View File
@@ -3687,6 +3687,7 @@ namespace ts {
OmitParameterModifiers = 1 << 13, // Omit modifiers on parameters
UseAliasDefinedOutsideCurrentScope = 1 << 14, // Allow non-visible aliases
UseSingleQuotesForStringLiteralType = 1 << 28, // Use single quotes for string literal type
PreserveVacuousIntersections = 1 << 29, // uh oh...
// Error handling
AllowThisInObjectLiteral = 1 << 15,
@@ -3730,6 +3731,7 @@ namespace ts {
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.
UseSingleQuotesForStringLiteralType = 1 << 28, // Use single quotes for string literal type
PreserveVacuousIntersections = 1 << 29, // uh oh
// Error Handling
AllowUniqueESSymbolType = 1 << 20, // This is bit 20 to align with the same bit in `NodeBuilderFlags`
@@ -3749,7 +3751,7 @@ namespace ts {
NodeBuilderFlagsMask = NoTruncation | WriteArrayAsGenericType | UseStructuralFallback | WriteTypeArgumentsOfSignature |
UseFullyQualifiedType | SuppressAnyReturnType | MultilineObjectLiterals | WriteClassExpressionAsTypeLiteral |
UseTypeOfFunction | OmitParameterModifiers | UseAliasDefinedOutsideCurrentScope | AllowUniqueESSymbolType | InTypeAlias |
UseSingleQuotesForStringLiteralType,
UseSingleQuotesForStringLiteralType | PreserveVacuousIntersections,
}
export const enum SymbolFormatFlags {