Numeric literals assignable to enum literals only when values match (#51561)

* Numeric literal assignable to enum literal only when values match

* Accept new baselines

* Update compiler sources

* Accept new baselines

* Fix test runner

* Any numeric literal type is assignable to a computed numeric enum type
This commit is contained in:
Anders Hejlsberg
2022-11-16 18:56:01 -08:00
committed by GitHub
parent e99c935927
commit 7b85cd6b72
14 changed files with 148 additions and 47 deletions
+18 -15
View File
@@ -386,6 +386,7 @@ export const enum CheckMode {
/** @internal */
export const enum SignatureCheckMode {
None = 0,
BivariantCallback = 1 << 0,
StrictCallback = 1 << 1,
IgnoreReturnTypes = 1 << 2,
@@ -476,7 +477,7 @@ function SymbolLinks(this: SymbolLinks) {
}
function NodeLinks(this: NodeLinks) {
this.flags = 0;
this.flags = NodeCheckFlags.None;
}
/** @internal */
@@ -1473,7 +1474,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function createSymbol(flags: SymbolFlags, name: __String, checkFlags?: CheckFlags) {
symbolCount++;
const symbol = (new Symbol(flags | SymbolFlags.Transient, name) as TransientSymbol);
symbol.checkFlags = checkFlags || 0;
symbol.checkFlags = checkFlags || CheckFlags.None;
return symbol;
}
@@ -4543,7 +4544,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return new Type(checker, flags);
}
function createIntrinsicType(kind: TypeFlags, intrinsicName: string, objectFlags: ObjectFlags = 0): IntrinsicType {
function createIntrinsicType(kind: TypeFlags, intrinsicName: string, objectFlags = ObjectFlags.None): IntrinsicType {
const type = createType(kind) as IntrinsicType;
type.intrinsicName = intrinsicName;
type.objectFlags = objectFlags;
@@ -8659,7 +8660,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function formatUnionTypes(types: readonly Type[]): Type[] {
const result: Type[] = [];
let flags: TypeFlags = 0;
let flags = 0 as TypeFlags;
for (let i = 0; i < types.length; i++) {
const t = types[i];
flags |= t.flags;
@@ -14750,7 +14751,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const minLength = countWhere(elementFlags, f => !!(f & (ElementFlags.Required | ElementFlags.Variadic)));
let typeParameters: TypeParameter[] | undefined;
const properties: Symbol[] = [];
let combinedFlags: ElementFlags = 0;
let combinedFlags = 0 as ElementFlags;
if (arity) {
typeParameters = new Array(arity);
for (let i = 0; i < arity; i++) {
@@ -15114,7 +15115,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return types[0];
}
let typeSet: Type[] | undefined = [];
const includes = addTypesToUnion(typeSet, 0, types);
const includes = addTypesToUnion(typeSet, 0 as TypeFlags, types);
if (unionReduction !== UnionReduction.None) {
if (includes & TypeFlags.AnyOrUnknown) {
return includes & TypeFlags.Any ?
@@ -15429,7 +15430,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// for intersections of types with signatures can be deterministic.
function getIntersectionType(types: readonly Type[], aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], noSupertypeReduction?: boolean): Type {
const typeMembershipMap: Map<string, Type> = new Map();
const includes = addTypesToIntersection(typeMembershipMap, 0, types);
const includes = addTypesToIntersection(typeMembershipMap, 0 as TypeFlags, types);
const typeSet: Type[] = arrayFrom(typeMembershipMap.values());
// An intersection type is considered empty if it contains
// the type never, or
@@ -18441,7 +18442,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function isSignatureAssignableTo(source: Signature,
target: Signature,
ignoreReturnTypes: boolean): boolean {
return compareSignaturesRelated(source, target, ignoreReturnTypes ? SignatureCheckMode.IgnoreReturnTypes : 0, /*reportErrors*/ false,
return compareSignaturesRelated(source, target, ignoreReturnTypes ? SignatureCheckMode.IgnoreReturnTypes : SignatureCheckMode.None, /*reportErrors*/ false,
/*errorReporter*/ undefined, /*errorReporter*/ undefined, compareTypesAssignable, /*reportUnreliableMarkers*/ undefined) !== Ternary.False;
}
@@ -18757,11 +18758,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive && !(relation === strictSubtypeRelation && isEmptyAnonymousObjectType(source) && !(getObjectFlags(source) & ObjectFlags.FreshLiteral))) return true;
if (relation === assignableRelation || relation === comparableRelation) {
if (s & TypeFlags.Any) return true;
// Type number or any numeric literal type is assignable to any numeric enum type or any
// numeric enum literal type. This rule exists for backwards compatibility reasons because
// bit-flag enum types sometimes look like literal enum types with numeric literal values.
if (s & (TypeFlags.Number | TypeFlags.NumberLiteral) && !(s & TypeFlags.EnumLiteral) && (
t & TypeFlags.Enum || relation === assignableRelation && t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral)) return true;
// Type number is assignable to any computed numeric enum type or any numeric enum literal type, and
// a numeric literal type is assignable any computed numeric enum type or any numeric enum literal type
// with a matching value. These rules exist such that enums can be used for bit-flag purposes.
if (s & TypeFlags.Number && (t & TypeFlags.Enum || t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral)) return true;
if (s & TypeFlags.NumberLiteral && !(s & TypeFlags.EnumLiteral) && (t & TypeFlags.Enum ||
t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral &&
(source as NumberLiteralType).value === (target as NumberLiteralType).value)) return true;
// Anything is assignable to a union containing undefined, null, and {}
if (isUnknownLikeUnionType(target)) return true;
}
@@ -19745,7 +19748,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (!(expandingFlags & ExpandingFlags.Target) && isDeeplyNestedType(target, targetStack, targetDepth)) expandingFlags |= ExpandingFlags.Target;
}
let originalHandler: typeof outofbandVarianceMarkerHandler;
let propagatingVarianceFlags: RelationComparisonResult = 0;
let propagatingVarianceFlags = 0 as RelationComparisonResult;
if (outofbandVarianceMarkerHandler) {
originalHandler = outofbandVarianceMarkerHandler;
outofbandVarianceMarkerHandler = onlyUnreliable => {
@@ -22863,7 +22866,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0, contravariant = false) {
function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority = InferencePriority.None, contravariant = false) {
let bivariant = false;
let propagationType: Type;
let inferencePriority: number = InferencePriority.MaxValue;
+2 -1
View File
@@ -88,6 +88,7 @@ interface LoopOutParameter {
}
const enum LoopOutParameterFlags {
None = 0,
Body = 1 << 0, // Modified in the body of the iteration statement
Initializer = 1 << 1, // Set in the initializer of a ForStatement
}
@@ -3488,7 +3489,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile
const checkFlags = resolver.getNodeCheckFlags(decl);
if (checkFlags & NodeCheckFlags.NeedsLoopOutParameter || hasCapturedBindingsInForHead) {
const outParamName = factory.createUniqueName("out_" + idText(name));
let flags: LoopOutParameterFlags = 0;
let flags = LoopOutParameterFlags.None;
if (checkFlags & NodeCheckFlags.NeedsLoopOutParameter) {
flags |= LoopOutParameterFlags.Body;
}
+2 -1
View File
@@ -25,6 +25,7 @@ const enum ES2017SubstitutionFlags {
}
const enum ContextFlags {
None = 0,
NonTopLevel = 1 << 0,
HasLexicalThis = 1 << 1
}
@@ -66,7 +67,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile
/** A set of node IDs for generated super accessors (variable statements). */
const substitutedSuperAccessors: boolean[] = [];
let contextFlags: ContextFlags = 0;
let contextFlags = ContextFlags.None;
// Save the previous transformation hooks.
const previousOnEmitNode = context.onEmitNode;
+29 -25
View File
@@ -5514,6 +5514,7 @@ export const enum EnumKind {
/** @internal */
export const enum CheckFlags {
None = 0,
Instantiated = 1 << 0, // Instantiated symbol
SyntheticProperty = 1 << 1, // Property in union or intersection type
SyntheticMethod = 1 << 2, // Method in union or intersection type
@@ -5611,31 +5612,32 @@ export interface PatternAmbientModule {
/** @internal */
export const enum NodeCheckFlags {
TypeChecked = 0x00000001, // Node has been type checked
LexicalThis = 0x00000002, // Lexical 'this' reference
CaptureThis = 0x00000004, // Lexical 'this' used in body
CaptureNewTarget = 0x00000008, // Lexical 'new.target' used in body
SuperInstance = 0x00000100, // Instance 'super' reference
SuperStatic = 0x00000200, // Static 'super' reference
ContextChecked = 0x00000400, // Contextual types have been assigned
MethodWithSuperPropertyAccessInAsync = 0x00000800, // A method that contains a SuperProperty access in an async context.
MethodWithSuperPropertyAssignmentInAsync = 0x00001000, // A method that contains a SuperProperty assignment in an async context.
CaptureArguments = 0x00002000, // Lexical 'arguments' used in body
EnumValuesComputed = 0x00004000, // Values for enum members have been computed, and any errors have been reported for them.
LexicalModuleMergesWithClass = 0x00008000, // Instantiated lexical module declaration is merged with a previous class declaration.
LoopWithCapturedBlockScopedBinding = 0x00010000, // Loop that contains block scoped variable captured in closure
ContainsCapturedBlockScopeBinding = 0x00020000, // Part of a loop that contains block scoped variable captured in closure
CapturedBlockScopedBinding = 0x00040000, // Block-scoped binding that is captured in some function
BlockScopedBindingInLoop = 0x00080000, // Block-scoped binding with declaration nested inside iteration statement
ClassWithBodyScopedClassBinding = 0x00100000, // Decorated class that contains a binding to itself inside of the class body.
BodyScopedClassBinding = 0x00200000, // Binding to a decorated class inside of the class's body.
NeedsLoopOutParameter = 0x00400000, // Block scoped binding whose value should be explicitly copied outside of the converted loop
AssignmentsMarked = 0x00800000, // Parameter assignments have been marked
ClassWithConstructorReference = 0x01000000, // Class that contains a binding to its constructor inside of the class body.
ConstructorReferenceInClass = 0x02000000, // Binding to a class constructor inside of the class's body.
ContainsClassWithPrivateIdentifiers = 0x04000000, // Marked on all block-scoped containers containing a class with private identifiers.
ContainsSuperPropertyInStaticInitializer = 0x08000000, // Marked on all block-scoped containers containing a static initializer with 'super.x' or 'super[x]'.
InCheckIdentifier = 0x10000000,
None = 0,
TypeChecked = 1 << 0, // Node has been type checked
LexicalThis = 1 << 1, // Lexical 'this' reference
CaptureThis = 1 << 2, // Lexical 'this' used in body
CaptureNewTarget = 1 << 3, // Lexical 'new.target' used in body
SuperInstance = 1 << 4, // Instance 'super' reference
SuperStatic = 1 << 5, // Static 'super' reference
ContextChecked = 1 << 6, // Contextual types have been assigned
MethodWithSuperPropertyAccessInAsync = 1 << 7, // A method that contains a SuperProperty access in an async context.
MethodWithSuperPropertyAssignmentInAsync = 1 << 8, // A method that contains a SuperProperty assignment in an async context.
CaptureArguments = 1 << 9, // Lexical 'arguments' used in body
EnumValuesComputed = 1 << 10, // Values for enum members have been computed, and any errors have been reported for them.
LexicalModuleMergesWithClass = 1 << 11, // Instantiated lexical module declaration is merged with a previous class declaration.
LoopWithCapturedBlockScopedBinding = 1 << 12, // Loop that contains block scoped variable captured in closure
ContainsCapturedBlockScopeBinding = 1 << 13, // Part of a loop that contains block scoped variable captured in closure
CapturedBlockScopedBinding = 1 << 14, // Block-scoped binding that is captured in some function
BlockScopedBindingInLoop = 1 << 15, // Block-scoped binding with declaration nested inside iteration statement
ClassWithBodyScopedClassBinding = 1 << 16, // Decorated class that contains a binding to itself inside of the class body.
BodyScopedClassBinding = 1 << 17, // Binding to a decorated class inside of the class's body.
NeedsLoopOutParameter = 1 << 18, // Block scoped binding whose value should be explicitly copied outside of the converted loop
AssignmentsMarked = 1 << 19, // Parameter assignments have been marked
ClassWithConstructorReference = 1 << 20, // Class that contains a binding to its constructor inside of the class body.
ConstructorReferenceInClass = 1 << 21, // Binding to a class constructor inside of the class's body.
ContainsClassWithPrivateIdentifiers = 1 << 22, // Marked on all block-scoped containers containing a class with private identifiers.
ContainsSuperPropertyInStaticInitializer = 1 << 23, // Marked on all block-scoped containers containing a static initializer with 'super.x' or 'super[x]'.
InCheckIdentifier = 1 << 24,
}
/** @internal */
@@ -5842,6 +5844,7 @@ export interface EnumType extends Type {
// are specific to certain types and reuse the same bit position. Those ObjectFlags require a check
// for a certain TypeFlags value to determine their meaning.
export const enum ObjectFlags {
None = 0,
Class = 1 << 0, // Class
Interface = 1 << 1, // Interface
Reference = 1 << 2, // Generic type reference
@@ -6384,6 +6387,7 @@ export type TypeMapper =
| { kind: TypeMapKind.Composite | TypeMapKind.Merged, mapper1: TypeMapper, mapper2: TypeMapper };
export const enum InferencePriority {
None = 0,
NakedTypeVariable = 1 << 0, // Naked type variable in union or intersection type
SpeculativeTuple = 1 << 1, // Speculative tuple inference
SubstituteSource = 1 << 2, // Source of inference originated within a substitution type's substitute
+1
View File
@@ -17,6 +17,7 @@ export const anyContext: readonly ContextPredicate[] = emptyArray;
/** @internal */
export const enum RuleAction {
None = 0,
StopProcessingSpaceActions = 1 << 0,
StopProcessingTokenActions = 1 << 1,
InsertSpace = 1 << 2,
+1 -1
View File
@@ -22,7 +22,7 @@ function getRulesMap(): RulesMap {
* cannot be applied at the same position.
*/
function getRuleActionExclusion(ruleAction: RuleAction): RuleAction {
let mask: RuleAction = 0;
let mask = RuleAction.None;
if (ruleAction & RuleAction.StopProcessingSpaceActions) {
mask |= RuleAction.ModifySpaceAction;
}
+2 -1
View File
@@ -1,6 +1,7 @@
import * as ts from "../_namespaces/ts";
const enum ChangedPart {
none = 0,
references = 1 << 0,
importsAndExports = 1 << 1,
program = 1 << 2
@@ -32,7 +33,7 @@ export class SourceText implements ts.IScriptSnapshot {
constructor(private references: string,
private importsAndExports: string,
private program: string,
private changedPart: ChangedPart = 0,
private changedPart = ChangedPart.none,
private version = 0) {
}
+2
View File
@@ -6719,6 +6719,7 @@ declare namespace ts {
interface EnumType extends Type {
}
enum ObjectFlags {
None = 0,
Class = 1,
Interface = 2,
Reference = 4,
@@ -6889,6 +6890,7 @@ declare namespace ts {
declaration?: IndexSignatureDeclaration;
}
enum InferencePriority {
None = 0,
NakedTypeVariable = 1,
SpeculativeTuple = 2,
SubstituteSource = 4,
+2
View File
@@ -2783,6 +2783,7 @@ declare namespace ts {
interface EnumType extends Type {
}
enum ObjectFlags {
None = 0,
Class = 1,
Interface = 2,
Reference = 4,
@@ -2953,6 +2954,7 @@ declare namespace ts {
declaration?: IndexSignatureDeclaration;
}
enum InferencePriority {
None = 0,
NakedTypeVariable = 1,
SpeculativeTuple = 2,
SubstituteSource = 4,
@@ -1,5 +1,7 @@
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/enumAssignability.ts(9,1): error TS2322: Type 'F' is not assignable to type 'E'.
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/enumAssignability.ts(10,1): error TS2322: Type 'E' is not assignable to type 'F'.
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/enumAssignability.ts(11,1): error TS2322: Type '1' is not assignable to type 'E'.
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/enumAssignability.ts(12,1): error TS2322: Type '1' is not assignable to type 'F'.
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/enumAssignability.ts(29,9): error TS2322: Type 'E' is not assignable to type 'string'.
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/enumAssignability.ts(30,9): error TS2322: Type 'E' is not assignable to type 'boolean'.
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/enumAssignability.ts(31,9): error TS2322: Type 'E' is not assignable to type 'Date'.
@@ -25,7 +27,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/enumAssi
'E' is assignable to the constraint of type 'B', but 'B' could be instantiated with a different subtype of constraint 'E'.
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/enumAssignability.ts (20 errors) ====
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/enumAssignability.ts (22 errors) ====
// enums assignable to number, any, Object, errors unless otherwise noted
enum E { A }
@@ -41,7 +43,11 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/enumAssi
~
!!! error TS2322: Type 'E' is not assignable to type 'F'.
e = 1; // ok
~
!!! error TS2322: Type '1' is not assignable to type 'E'.
f = 1; // ok
~
!!! error TS2322: Type '1' is not assignable to type 'F'.
var x: number = e; // ok
x = f; // ok
@@ -1,11 +1,13 @@
tests/cases/compiler/enumAssignmentCompat.ts(26,5): error TS2322: Type 'typeof W' is not assignable to type 'number'.
tests/cases/compiler/enumAssignmentCompat.ts(28,5): error TS2322: Type 'W' is not assignable to type 'typeof W'.
tests/cases/compiler/enumAssignmentCompat.ts(30,5): error TS2322: Type 'number' is not assignable to type 'typeof W'.
tests/cases/compiler/enumAssignmentCompat.ts(31,5): error TS2322: Type '4' is not assignable to type 'W.a'.
tests/cases/compiler/enumAssignmentCompat.ts(32,5): error TS2322: Type 'W' is not assignable to type 'WStatic'.
tests/cases/compiler/enumAssignmentCompat.ts(33,5): error TS2322: Type 'number' is not assignable to type 'WStatic'.
tests/cases/compiler/enumAssignmentCompat.ts(34,5): error TS2322: Type '3' is not assignable to type 'W'.
==== tests/cases/compiler/enumAssignmentCompat.ts (5 errors) ====
==== tests/cases/compiler/enumAssignmentCompat.ts (7 errors) ====
module W {
export class D { }
}
@@ -43,6 +45,8 @@ tests/cases/compiler/enumAssignmentCompat.ts(33,5): error TS2322: Type 'number'
~
!!! error TS2322: Type 'number' is not assignable to type 'typeof W'.
var e: typeof W.a = 4;
~
!!! error TS2322: Type '4' is not assignable to type 'W.a'.
var f: WStatic = W.a; // error
~
!!! error TS2322: Type 'W' is not assignable to type 'WStatic'.
@@ -50,6 +54,8 @@ tests/cases/compiler/enumAssignmentCompat.ts(33,5): error TS2322: Type 'number'
~
!!! error TS2322: Type 'number' is not assignable to type 'WStatic'.
var h: W = 3;
~
!!! error TS2322: Type '3' is not assignable to type 'W'.
var i: W = W.a;
i = W.a;
W.D;
@@ -1,11 +1,13 @@
tests/cases/compiler/enumAssignmentCompat2.ts(25,5): error TS2322: Type 'typeof W' is not assignable to type 'number'.
tests/cases/compiler/enumAssignmentCompat2.ts(27,5): error TS2322: Type 'W' is not assignable to type 'typeof W'.
tests/cases/compiler/enumAssignmentCompat2.ts(29,5): error TS2322: Type 'number' is not assignable to type 'typeof W'.
tests/cases/compiler/enumAssignmentCompat2.ts(30,5): error TS2322: Type '4' is not assignable to type 'W.a'.
tests/cases/compiler/enumAssignmentCompat2.ts(31,5): error TS2322: Type 'W' is not assignable to type 'WStatic'.
tests/cases/compiler/enumAssignmentCompat2.ts(32,5): error TS2322: Type 'number' is not assignable to type 'WStatic'.
tests/cases/compiler/enumAssignmentCompat2.ts(33,5): error TS2322: Type '3' is not assignable to type 'W'.
==== tests/cases/compiler/enumAssignmentCompat2.ts (5 errors) ====
==== tests/cases/compiler/enumAssignmentCompat2.ts (7 errors) ====
enum W {
a, b, c,
@@ -42,6 +44,8 @@ tests/cases/compiler/enumAssignmentCompat2.ts(32,5): error TS2322: Type 'number'
~
!!! error TS2322: Type 'number' is not assignable to type 'typeof W'.
var e: typeof W.a = 4;
~
!!! error TS2322: Type '4' is not assignable to type 'W.a'.
var f: WStatic = W.a; // error
~
!!! error TS2322: Type 'W' is not assignable to type 'WStatic'.
@@ -49,6 +53,8 @@ tests/cases/compiler/enumAssignmentCompat2.ts(32,5): error TS2322: Type 'number'
~
!!! error TS2322: Type 'number' is not assignable to type 'WStatic'.
var h: W = 3;
~
!!! error TS2322: Type '3' is not assignable to type 'W'.
var i: W = W.a;
i = W.a;
W.D;
@@ -0,0 +1,36 @@
tests/cases/compiler/enumAssignmentCompat5.ts(12,1): error TS2322: Type '4' is not assignable to type 'E'.
tests/cases/compiler/enumAssignmentCompat5.ts(14,1): error TS2322: Type '2' is not assignable to type 'E.A'.
tests/cases/compiler/enumAssignmentCompat5.ts(20,5): error TS2322: Type '1' is not assignable to type 'Computed.A'.
==== tests/cases/compiler/enumAssignmentCompat5.ts (3 errors) ====
enum E {
A, B, C
}
enum Computed {
A = 1 << 1,
B = 1 << 2,
C = 1 << 3,
}
let n: number;
let e: E = n; // ok because it's too inconvenient otherwise
e = 0; // ok, in range
e = 4; // ok, out of range, but allowed computed enums don't have all members
~
!!! error TS2322: Type '4' is not assignable to type 'E'.
let a: E.A = 0; // ok, A === 0
a = 2; // error, 2 !== 0
~
!!! error TS2322: Type '2' is not assignable to type 'E.A'.
a = n; // ok
let c: Computed = n; // ok
c = n; // ok
c = 4; // ok
let ca: Computed.A = 1; // error, Computed.A isn't a literal type because Computed has no enum literals
~~
!!! error TS2322: Type '1' is not assignable to type 'Computed.A'.
@@ -0,0 +1,32 @@
tests/cases/conformance/types/primitives/enum/validEnumAssignments.ts(26,1): error TS2322: Type '-1' is not assignable to type 'E'.
==== tests/cases/conformance/types/primitives/enum/validEnumAssignments.ts (1 errors) ====
enum E {
A,
B
}
var n: number;
var a: any;
var e: E;
n = e;
n = E.A;
a = n;
a = e;
a = E.A;
e = e;
e = E.A;
e = E.B;
e = n;
e = null;
e = undefined;
e = 1;
e = 1.;
e = 1.0;
e = -1;
~
!!! error TS2322: Type '-1' is not assignable to type 'E'.