From 6cd5a4dac9599122eff78d016a82ac0d362850ab Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 10 Dec 2015 11:03:45 -0800 Subject: [PATCH] Compare enums semi-structurally. 1. Unqualified names must match. 2. Target contains members with same names as all source members. --- src/compiler/checker.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 50a3aee995..0f04daf298 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5040,6 +5040,11 @@ namespace ts { if (source === undefinedType) return Ternary.True; if (source === nullType && target !== undefinedType) return Ternary.True; if (source.flags & TypeFlags.Enum && target === numberType) return Ternary.True; + if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum) { + if (result = enumRelatedTo(source, target)) { + return result; + } + } if (source.flags & TypeFlags.StringLiteral && target === stringType) return Ternary.True; if (relation === assignableRelation) { if (isTypeAny(source)) return Ternary.True; @@ -5750,6 +5755,25 @@ namespace ts { } return Ternary.False; } + + function enumRelatedTo(source: Type, target: Type) { + if (source.symbol.name !== target.symbol.name) { + return Ternary.False; + } + const sourceDecl = getMergedSymbol(source.symbol).valueDeclaration; + const targetDecl = getMergedSymbol(target.symbol).valueDeclaration; + const targetMembers = arrayToMap(targetDecl.members, member => getTextOfPropertyName(member.name)); + for (const member of sourceDecl.members) { + const name = getTextOfPropertyName(member.name); + if (!targetMembers[name]) { + reportError(Diagnostics.Property_0_is_missing_in_type_1, + name, + typeToString(target, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType)); + return Ternary.False; + } + } + return Ternary.True; + } } // Return true if the given type is part of a deeply nested chain of generic instantiations. We consider this to be the case