From 90d20f260a45ee8f08548fb420529748265d7248 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 28 Oct 2017 15:28:11 -0700 Subject: [PATCH] Redo subtype reduction with correct --noImplicitAny error reporting --- src/compiler/checker.ts | 45 +++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d1ad5f6f73202..72438fa27af87 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10551,7 +10551,11 @@ namespace ts { } if (type.flags & TypeFlags.Union) { const unionContext = context || createWideningContext(/*parent*/ undefined, /*propertyName*/ undefined, (type).types); - return getUnionType(sameMap((type).types, t => t.flags & TypeFlags.Nullable ? t : getWidenedTypeWithContext(t, unionContext))); + const widenedTypes = sameMap((type).types, t => t.flags & TypeFlags.Nullable ? t : getWidenedTypeWithContext(t, unionContext)); + // Widening an empty object literal transitions from a highly restrictive type to + // a highly inclusive one. For that reason we perform subtype reduction here if the + // union includes empty object types (e.g. reducing {} | string to just {}). + return getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType)); } if (isArrayType(type) || isTupleType(type)) { return createTypeReference((type).target, sameMap((type).typeArguments, getWidenedType)); @@ -10573,28 +10577,35 @@ namespace ts { */ function reportWideningErrorsInType(type: Type): boolean { let errorReported = false; - if (type.flags & TypeFlags.Union) { - for (const t of (type).types) { - if (reportWideningErrorsInType(t)) { + if (type.flags & TypeFlags.ContainsWideningType) { + if (type.flags & TypeFlags.Union) { + if (some((type).types, isEmptyObjectType)) { errorReported = true; } + else { + for (const t of (type).types) { + if (reportWideningErrorsInType(t)) { + errorReported = true; + } + } + } } - } - if (isArrayType(type) || isTupleType(type)) { - for (const t of (type).typeArguments) { - if (reportWideningErrorsInType(t)) { - errorReported = true; + if (isArrayType(type) || isTupleType(type)) { + for (const t of (type).typeArguments) { + if (reportWideningErrorsInType(t)) { + errorReported = true; + } } } - } - if (isObjectLiteralType(type)) { - for (const p of getPropertiesOfObjectType(type)) { - const t = getTypeOfSymbol(p); - if (t.flags & TypeFlags.ContainsWideningType) { - if (!reportWideningErrorsInType(t)) { - error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, symbolName(p), typeToString(getWidenedType(t))); + if (isObjectLiteralType(type)) { + for (const p of getPropertiesOfObjectType(type)) { + const t = getTypeOfSymbol(p); + if (t.flags & TypeFlags.ContainsWideningType) { + if (!reportWideningErrorsInType(t)) { + error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, symbolName(p), typeToString(getWidenedType(t))); + } + errorReported = true; } - errorReported = true; } } }