From b7439c1baf62f9ce18cde8ae8ec455f64b29ec15 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 19 Jun 2025 08:08:58 -0700 Subject: [PATCH 1/4] Use strict subtype relation in getCommonSupertype --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 76e81a959790b..a327c0ed49962 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25340,7 +25340,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // right is a supertype. const superTypeOrUnion = literalTypesWithSameBaseType(primaryTypes) ? getUnionType(primaryTypes) : - reduceLeft(primaryTypes, (s, t) => isTypeSubtypeOf(s, t) ? t : s)!; + reduceLeft(primaryTypes, (s, t) => isTypeStrictSubtypeOf(s, t) ? t : s)!; // Add any nullable types that occurred in the candidates back to the result. return primaryTypes === types ? superTypeOrUnion : getNullableType(superTypeOrUnion, getCombinedTypeFlags(types) & TypeFlags.Nullable); } From a6d3453117662e1eac62f5975f25fb2169f17595 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 20 Jun 2025 15:25:02 -0400 Subject: [PATCH 2/4] Find single strict supertype, otherwise use assignability relation --- src/compiler/checker.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a327c0ed49962..77974932889cd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25340,11 +25340,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // right is a supertype. const superTypeOrUnion = literalTypesWithSameBaseType(primaryTypes) ? getUnionType(primaryTypes) : - reduceLeft(primaryTypes, (s, t) => isTypeStrictSubtypeOf(s, t) ? t : s)!; + getSingleCommonSupertype(primaryTypes) // Add any nullable types that occurred in the candidates back to the result. return primaryTypes === types ? superTypeOrUnion : getNullableType(superTypeOrUnion, getCombinedTypeFlags(types) & TypeFlags.Nullable); } + function getSingleCommonSupertype(types: Type[]) { + const candidate = reduceLeft(types, (s, t) => isTypeStrictSubtypeOf(s, t) ? t : s)!; + return every(types, t => t === candidate || isTypeStrictSubtypeOf(t, candidate)) ? + candidate : + reduceLeft(types, (s, t) => isTypeAssignableTo(s, t) ? t : s)!; + } + // Return the leftmost type for which no type to the right is a subtype. function getCommonSubtype(types: Type[]) { return reduceLeft(types, (s, t) => isTypeSubtypeOf(t, s) ? t : s)!; From 544f4d7b39d936cb57297c6149802205426a0bdf Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 20 Jun 2025 16:49:02 -0400 Subject: [PATCH 3/4] Try to find single strict supertype, otherwise do previous behavior --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 77974932889cd..9dc463d3cc9f1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25349,7 +25349,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const candidate = reduceLeft(types, (s, t) => isTypeStrictSubtypeOf(s, t) ? t : s)!; return every(types, t => t === candidate || isTypeStrictSubtypeOf(t, candidate)) ? candidate : - reduceLeft(types, (s, t) => isTypeAssignableTo(s, t) ? t : s)!; + reduceLeft(types, (s, t) => isTypeSubtypeOf(s, t) ? t : s)!; } // Return the leftmost type for which no type to the right is a subtype. From cb554a834ee17236acb2d34f545b14ab43b68f8e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 20 Jun 2025 19:19:18 -0400 Subject: [PATCH 4/4] Fix lint issue and add comment --- src/compiler/checker.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9dc463d3cc9f1..ba8ec48a39eff 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25340,12 +25340,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // right is a supertype. const superTypeOrUnion = literalTypesWithSameBaseType(primaryTypes) ? getUnionType(primaryTypes) : - getSingleCommonSupertype(primaryTypes) + getSingleCommonSupertype(primaryTypes); // Add any nullable types that occurred in the candidates back to the result. return primaryTypes === types ? superTypeOrUnion : getNullableType(superTypeOrUnion, getCombinedTypeFlags(types) & TypeFlags.Nullable); } function getSingleCommonSupertype(types: Type[]) { + // First, find the leftmost type for which no type to the right is a strict supertype, and if that + // type is a strict supertype of all other candidates, return it. Otherwise, return the leftmost type + // for which no type to the right is a (regular) supertype. const candidate = reduceLeft(types, (s, t) => isTypeStrictSubtypeOf(s, t) ? t : s)!; return every(types, t => t === candidate || isTypeStrictSubtypeOf(t, candidate)) ? candidate :