diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ac02f917827e4..ba7bf191be784 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16540,7 +16540,7 @@ namespace ts { if (!targetProperty) continue outer; if (sourceProperty === targetProperty) continue; // We compare the source property to the target in the context of a single discriminant type. - const related = propertyRelatedTo(source, target, sourceProperty, targetProperty, _ => combination[i], /*reportErrors*/ false, IntersectionState.None); + const related = propertyRelatedTo(source, target, sourceProperty, targetProperty, _ => combination[i], /*reportErrors*/ false, IntersectionState.None, /*skipOptional*/ strictNullChecks || relation === comparableRelation); // If the target property could not be found, or if the properties were not related, // then this constituent is not a match. if (!related) { @@ -16638,7 +16638,7 @@ namespace ts { } } - function propertyRelatedTo(source: Type, target: Type, sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function propertyRelatedTo(source: Type, target: Type, sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean, intersectionState: IntersectionState, skipOptional: boolean): Ternary { const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp); const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp); if (sourcePropFlags & ModifierFlags.Private || targetPropFlags & ModifierFlags.Private) { @@ -16681,7 +16681,7 @@ namespace ts { return Ternary.False; } // When checking for comparability, be more lenient with optional properties. - if (relation !== comparableRelation && sourceProp.flags & SymbolFlags.Optional && !(targetProp.flags & SymbolFlags.Optional)) { + if (!skipOptional && sourceProp.flags & SymbolFlags.Optional && !(targetProp.flags & SymbolFlags.Optional)) { // TypeScript 1.0 spec (April 2014): 3.8.3 // S is a subtype of a type T, and T is a supertype of S if ... // S' and T are object types and, for each member M in T.. @@ -16811,7 +16811,7 @@ namespace ts { if (!(targetProp.flags & SymbolFlags.Prototype) && (!numericNamesOnly || isNumericLiteralName(name) || name === "length")) { const sourceProp = getPropertyOfType(source, name); if (sourceProp && sourceProp !== targetProp) { - const related = propertyRelatedTo(source, target, sourceProp, targetProp, getTypeOfSymbol, reportErrors, intersectionState); + const related = propertyRelatedTo(source, target, sourceProp, targetProp, getTypeOfSymbol, reportErrors, intersectionState, relation === comparableRelation); if (!related) { return Ternary.False; } diff --git a/tests/baselines/reference/unionRelationshipCheckPasses.js b/tests/baselines/reference/unionRelationshipCheckPasses.js new file mode 100644 index 0000000000000..65e90ed34e811 --- /dev/null +++ b/tests/baselines/reference/unionRelationshipCheckPasses.js @@ -0,0 +1,7 @@ +//// [unionRelationshipCheckPasses.ts] +const item: { foo?: undefined } | { foo: number } = null as any as { foo?: number | undefined }; + + +//// [unionRelationshipCheckPasses.js] +"use strict"; +var item = null; diff --git a/tests/baselines/reference/unionRelationshipCheckPasses.symbols b/tests/baselines/reference/unionRelationshipCheckPasses.symbols new file mode 100644 index 0000000000000..3fda4578bdbb3 --- /dev/null +++ b/tests/baselines/reference/unionRelationshipCheckPasses.symbols @@ -0,0 +1,7 @@ +=== tests/cases/compiler/unionRelationshipCheckPasses.ts === +const item: { foo?: undefined } | { foo: number } = null as any as { foo?: number | undefined }; +>item : Symbol(item, Decl(unionRelationshipCheckPasses.ts, 0, 5)) +>foo : Symbol(foo, Decl(unionRelationshipCheckPasses.ts, 0, 13)) +>foo : Symbol(foo, Decl(unionRelationshipCheckPasses.ts, 0, 35)) +>foo : Symbol(foo, Decl(unionRelationshipCheckPasses.ts, 0, 68)) + diff --git a/tests/baselines/reference/unionRelationshipCheckPasses.types b/tests/baselines/reference/unionRelationshipCheckPasses.types new file mode 100644 index 0000000000000..e0e582916bb9c --- /dev/null +++ b/tests/baselines/reference/unionRelationshipCheckPasses.types @@ -0,0 +1,10 @@ +=== tests/cases/compiler/unionRelationshipCheckPasses.ts === +const item: { foo?: undefined } | { foo: number } = null as any as { foo?: number | undefined }; +>item : { foo?: undefined; } | { foo: number; } +>foo : undefined +>foo : number +>null as any as { foo?: number | undefined } : { foo?: number | undefined; } +>null as any : any +>null : null +>foo : number | undefined + diff --git a/tests/cases/compiler/unionRelationshipCheckPasses.ts b/tests/cases/compiler/unionRelationshipCheckPasses.ts new file mode 100644 index 0000000000000..cec4cffbf08cd --- /dev/null +++ b/tests/cases/compiler/unionRelationshipCheckPasses.ts @@ -0,0 +1,2 @@ +// @strict: true +const item: { foo?: undefined } | { foo: number } = null as any as { foo?: number | undefined };