diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 44d6ca66853..c693af4f0ac 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12176,6 +12176,9 @@ namespace ts { UnionReduction.Literal, aliasSymbol, aliasTypeArguments); } } + else if (includes & TypeFlags.Object && hasPropertiesWithDisjointTypes(typeSet)) { + result = neverType; + } else { result = createIntersectionType(typeSet, aliasSymbol, aliasTypeArguments); } @@ -12184,6 +12187,38 @@ namespace ts { return result; } + function hasPropertiesWithDisjointTypes(typeSet: Type[]) { + const members = createMap(); + for (const type of typeSet) { + if (type.flags & TypeFlags.Object && !isGenericMappedType(type) && !isArrayType(type) && !isTupleType(type)) { + for (const prop of getPropertiesOfObjectType(type)) { + if (prop.flags & SymbolFlags.Property) { + const name = prop.escapedName; + const cached = members.get(name); + if (!cached) { + members.set(name, prop); + } + else if (!isArray(cached)) { + members.set(name, [cached, prop]); + } + else { + cached.push(prop); + } + } + } + } + } + for (const props of arrayFrom(members.values())) { + if (isArray(props)) { + const types = map(props, getTypeOfSymbol); + if (every(types, isLiteralType) && getIntersectionType(types).flags & TypeFlags.Never) { + return true; + } + } + } + return false; + } + function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { @@ -16256,7 +16291,6 @@ namespace ts { } function propertiesRelatedTo(source: Type, target: Type, reportErrors: boolean, excludedProperties: UnderscoreEscapedMap | undefined, intersectionState: IntersectionState): Ternary { - if (relation === identityRelation) { return propertiesIdenticalTo(source, target, excludedProperties); }