diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ad3f3b71f29fb..25a05cf82ec74 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14706,11 +14706,17 @@ namespace ts { if (isFreshLiteralType(target)) { target = (target).regularType; } - if (source === target || - relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) || - relation !== identityRelation && isSimpleTypeRelatedTo(source, target, relation)) { + if (source === target) { return true; } + if (relation !== identityRelation) { + if (relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) || isSimpleTypeRelatedTo(source, target, relation)) { + return true; + } + } + else { + if (!(source.flags === target.flags && source.flags & TypeFlags.Substructure)) return false; + } if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) { const related = relation.get(getRelationKey(source, target, IntersectionState.None, relation)); if (related !== undefined) { @@ -15048,6 +15054,12 @@ namespace ts { let source = getNormalizedType(originalSource, /*writing*/ false); let target = getNormalizedType(originalTarget, /*writing*/ true); + if (source === target) return Ternary.True; + + if (relation === identityRelation) { + return isIdenticalTo(source, target); + } + // Try to see if we're relating something like `Foo` -> `Bar | null | undefined`. // If so, reporting the `null` and `undefined` in the type is hardly useful. // First, see if we're even relating an object type to a union. @@ -15061,17 +15073,11 @@ namespace ts { (target as UnionType).types.length <= 3 && maybeTypeOfKind(target, TypeFlags.Nullable)) { const nullStrippedTarget = extractTypesOfKind(target, ~TypeFlags.Nullable); if (!(nullStrippedTarget.flags & (TypeFlags.Union | TypeFlags.Never))) { + if (source === nullStrippedTarget) return Ternary.True; target = nullStrippedTarget; } } - // both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases - if (source === target) return Ternary.True; - - if (relation === identityRelation) { - return isIdenticalTo(source, target); - } - if (relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) || isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True; @@ -15217,19 +15223,18 @@ namespace ts { } function isIdenticalTo(source: Type, target: Type): Ternary { - let result: Ternary; const flags = source.flags & target.flags; - if (flags & TypeFlags.Object || flags & TypeFlags.IndexedAccess || flags & TypeFlags.Conditional || flags & TypeFlags.Index || flags & TypeFlags.Substitution) { - return recursiveTypeRelatedTo(source, target, /*reportErrors*/ false, IntersectionState.None); + if (!(flags & TypeFlags.Substructure)) { + return Ternary.False; } - if (flags & (TypeFlags.Union | TypeFlags.Intersection)) { - if (result = eachTypeRelatedToSomeType(source, target)) { - if (result &= eachTypeRelatedToSomeType(target, source)) { - return result; - } + if (flags & TypeFlags.UnionOrIntersection) { + let result = eachTypeRelatedToSomeType(source, target); + if (result) { + result &= eachTypeRelatedToSomeType(target, source); } + return result; } - return Ternary.False; + return recursiveTypeRelatedTo(source, target, /*reportErrors*/ false, IntersectionState.None); } function getTypeOfPropertyInTypes(types: Type[], name: __String) { @@ -18390,7 +18395,7 @@ namespace ts { } function isTypeOrBaseIdenticalTo(s: Type, t: Type) { - return isTypeIdenticalTo(s, t) || !!(s.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) && isTypeIdenticalTo(getBaseTypeOfLiteralType(s), t); + return isTypeIdenticalTo(s, t) || !!(t.flags & TypeFlags.String && s.flags & TypeFlags.StringLiteral || t.flags & TypeFlags.Number && s.flags & TypeFlags.NumberLiteral); } function isTypeCloselyMatchedBy(s: Type, t: Type) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9b913c2f17d00..11d20b32ca9f4 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4318,6 +4318,8 @@ namespace ts { ObjectFlagsType = Any | Nullable | Never | Object | Union | Intersection, /* @internal */ Simplifiable = IndexedAccess | Conditional, + /* @internal */ + Substructure = Object | Union | Intersection | Index | IndexedAccess | Conditional | Substitution, // 'Narrowable' types are types where narrowing actually narrows. // This *should* be every type other than null, undefined, void, and never Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive,