diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index c83e11fc2a4a0..2da76df3ac856 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -57,6 +57,7 @@ import { ElementAccessExpression, EntityNameExpression, EnumDeclaration, + EnumLiteralExpression, escapeLeadingUnderscores, every, ExportAssignment, @@ -2272,6 +2273,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { case SyntaxKind.ClassDeclaration: return declareClassMember(node, symbolFlags, symbolExcludes); + case SyntaxKind.EnumLiteralExpression: case SyntaxKind.EnumDeclaration: return declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes); @@ -3044,6 +3046,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { return bindBlockScopedDeclaration(node as Declaration, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes); case SyntaxKind.TypeAliasDeclaration: return bindBlockScopedDeclaration(node as Declaration, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes); + case SyntaxKind.EnumLiteralExpression: + return bindEnumLiteralExpression(node as EnumLiteralExpression); case SyntaxKind.EnumDeclaration: return bindEnumDeclaration(node as EnumDeclaration); case SyntaxKind.ModuleDeclaration: @@ -3655,6 +3659,17 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { : bindBlockScopedDeclaration(node, SymbolFlags.RegularEnum, SymbolFlags.RegularEnumExcludes); } + function bindEnumLiteralExpression(node: EnumLiteralExpression) { + Debug.assert(isVariableDeclaration(node.parent)); + + const varSymbol: Symbol = node.parent.symbol; + node.symbol = varSymbol; + varSymbol.flags |= isEnumConst(node) ? SymbolFlags.ConstEnum : SymbolFlags.RegularEnum; + varSymbol.flags &= ~(SymbolFlags.Assignment | SymbolFlags.Variable); + varSymbol.exports ??= createSymbolTable(); + appendIfUnique(varSymbol.declarations, node); + } + function bindVariableDeclarationOrBindingElement(node: VariableDeclaration | BindingElement) { if (inStrictMode) { checkStrictModeEvalOrArguments(node, node.name); @@ -3914,6 +3929,7 @@ export function getContainerFlags(node: Node): ContainerFlags { case SyntaxKind.ClassExpression: case SyntaxKind.ClassDeclaration: case SyntaxKind.EnumDeclaration: + case SyntaxKind.EnumLiteralExpression: case SyntaxKind.ObjectLiteralExpression: case SyntaxKind.TypeLiteral: case SyntaxKind.JSDocTypeLiteral: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index caab75c99fa8a..c56909ab44a29 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -169,6 +169,7 @@ import { EntityNameOrEntityNameExpression, entityNameToString, EnumDeclaration, + EnumLiteralExpression, EnumMember, EnumType, equateValues, @@ -536,7 +537,10 @@ import { isEntityNameExpression, isEnumConst, isEnumDeclaration, + isEnumLiteralDeclaration, + isEnumLiteralExpression, isEnumMember, + isEnumTypeAnnotation, isExclusivelyTypeOnlyImportOrExport, isExpandoPropertyDeclaration, isExportAssignment, @@ -11984,7 +11988,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // getTypeOfSymbol dispatches some JS merges incorrectly because their symbol flags are not mutually exclusive. // Re-dispatch based on valueDeclaration.kind instead. - else if (isEnumDeclaration(declaration)) { + else if (isEnumDeclaration(declaration) || isEnumLiteralExpression(declaration)) { type = getTypeOfFuncClassEnumModule(symbol); } else if (isEnumMember(declaration)) { @@ -12876,7 +12880,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const memberTypeList: Type[] = []; if (symbol.declarations) { for (const declaration of symbol.declarations) { - if (declaration.kind === SyntaxKind.EnumDeclaration) { + if (declaration.kind === SyntaxKind.EnumDeclaration || declaration.kind === SyntaxKind.EnumLiteralExpression) { for (const member of (declaration as EnumDeclaration).members) { if (hasBindableName(member)) { const memberSymbol = getSymbolOfDeclaration(member); @@ -16706,6 +16710,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { links.resolvedSymbol = unknownSymbol; return links.resolvedType = checkExpressionCached(node.parent.expression); } + // `var MyEnum: enum = { FirstValue: 1, SecondValue: 2 }` should resolve to a union of the enum values. + if (node.parent && isEnumLiteralDeclaration(node.parent)) { + return links.resolvedType = checkExpressionCached(node.parent.initializer); + } let symbol: Symbol | undefined; let type: Type | undefined; const meaning = SymbolFlags.Type; @@ -16760,6 +16768,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.EnumDeclaration: + case SyntaxKind.EnumLiteralExpression: return declaration; } } @@ -41109,6 +41118,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkArrayLiteral(node as ArrayLiteralExpression, checkMode, forceTuple); case SyntaxKind.ObjectLiteralExpression: return checkObjectLiteral(node as ObjectLiteralExpression, checkMode); + case SyntaxKind.EnumLiteralExpression: + return checkEnumLiteralExpression(node as EnumLiteralExpression); case SyntaxKind.PropertyAccessExpression: return checkPropertyAccessExpression(node as PropertyAccessExpression, checkMode); case SyntaxKind.QualifiedName: @@ -44128,7 +44139,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkClassNameCollisionWithObject(name); } } - else if (isEnumDeclaration(node)) { + else if (isEnumDeclaration(node) || isEnumLiteralDeclaration(node)) { checkTypeNameIsReserved(name, Diagnostics.Enum_name_cannot_be_0); } } @@ -47033,16 +47044,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function computeEnumMemberValues(node: EnumDeclaration) { + function computeEnumMemberValues(node: EnumDeclaration | EnumLiteralExpression) { const nodeLinks = getNodeLinks(node); if (!(nodeLinks.flags & NodeCheckFlags.EnumValuesComputed)) { nodeLinks.flags |= NodeCheckFlags.EnumValuesComputed; - let autoValue: number | undefined = 0; + // EnumLiteralExpressions are essentially plain ObjectLiteralExpressions and can not have computed values. + const hasComputedValues = !isEnumLiteralExpression(node); + let autoValue: number | undefined = hasComputedValues ? 0 : undefined; let previous: EnumMember | undefined; for (const member of node.members) { const result = computeEnumMemberValue(member, autoValue, previous); getNodeLinks(member).enumMemberValue = result; - autoValue = typeof result.value === "number" ? result.value + 1 : undefined; + autoValue = (hasComputedValues && typeof result.value === "number") ? result.value + 1 : undefined; previous = member; } } @@ -47090,6 +47103,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const isConstEnum = isEnumConst(member.parent); const initializer = member.initializer!; const result = evaluate(initializer, member); + const isDecl = isEnumDeclaration(member.parent); if (result.value !== undefined) { if (isConstEnum && typeof result.value === "number" && !isFinite(result.value)) { error( @@ -47103,7 +47117,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error( initializer, Diagnostics._0_has_a_string_type_but_must_have_syntactically_recognizable_string_syntax_when_isolatedModules_is_enabled, - `${idText(member.parent.name)}.${getTextOfPropertyName(member.name)}`, + isDecl ? `${idText(member.parent.name)}.${getTextOfPropertyName(member.name)}` : `${member.parent.name}.${getTextOfPropertyName(member.name)}`, ); } } @@ -47191,6 +47205,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { addLazyDiagnostic(() => checkEnumDeclarationWorker(node)); } + function checkEnumLiteralExpression(node: EnumLiteralExpression) { + addLazyDiagnostic(() => checkEnumDeclarationWorker(node as any)); + return getTypeOfSymbol(getSymbolOfDeclaration(node)); + } + function checkEnumDeclarationWorker(node: EnumDeclaration) { // Grammar checking checkGrammarModifiers(node); @@ -47218,7 +47237,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const enumIsConst = isEnumConst(node); // check that const is placed\omitted on all enum declarations forEach(enumSymbol.declarations, decl => { - if (isEnumDeclaration(decl) && isEnumConst(decl) !== enumIsConst) { + if ((isEnumDeclaration(decl) || isEnumLiteralExpression(decl)) && isEnumConst(decl) !== enumIsConst) { error(getNameOfDeclaration(decl), Diagnostics.Enum_declarations_must_all_be_const_or_non_const); } }); @@ -48854,6 +48873,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ModuleDeclaration: copyLocallyVisibleExportSymbols(getSymbolOfDeclaration(location as ModuleDeclaration | SourceFile).exports!, meaning & SymbolFlags.ModuleMember); break; + case SyntaxKind.EnumLiteralExpression: case SyntaxKind.EnumDeclaration: copySymbols(getSymbolOfDeclaration(location as EnumDeclaration).exports!, meaning & SymbolFlags.EnumMember); break; @@ -49304,6 +49324,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // no other meta properties are valid syntax, thus no others should have symbols return undefined; } + else if (isEnumTypeAnnotation(node)) { + // Avoid symbolizing "enum" keywords in type annotations. + return undefined; + } } switch (node.kind) { @@ -49490,6 +49514,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isDeclarationNameOrImportPropertyName(node)) { const symbol = getSymbolAtLocation(node); if (symbol) { + if (symbol.valueDeclaration && isEnumLiteralDeclaration(symbol.valueDeclaration)) { + return getDeclaredTypeOfEnum(symbol); + } return getTypeOfSymbol(symbol); } return errorType; @@ -50352,6 +50379,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: case SyntaxKind.EnumMember: + case SyntaxKind.EnumLiteralExpression: case SyntaxKind.ObjectLiteralExpression: case SyntaxKind.FunctionDeclaration: case SyntaxKind.FunctionExpression: @@ -51329,6 +51357,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { findFirstModifierExcept(node, SyntaxKind.AwaitKeyword) : find(node.modifiers, isModifier); case SyntaxKind.EnumDeclaration: + case SyntaxKind.EnumLiteralExpression: return findFirstModifierExcept(node, SyntaxKind.ConstKeyword); default: Debug.assertNever(node); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 01a96579861f4..2bf986df72fbe 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -79,6 +79,7 @@ import { ensureTrailingDirectorySeparator, EntityName, EnumDeclaration, + EnumLiteralExpression, EnumMember, escapeJsxAttributeString, escapeLeadingUnderscores, @@ -1924,6 +1925,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return emitArrayLiteralExpression(node as ArrayLiteralExpression); case SyntaxKind.ObjectLiteralExpression: return emitObjectLiteralExpression(node as ObjectLiteralExpression); + case SyntaxKind.EnumLiteralExpression: + return emitEnumLiteralExpression(node as EnumLiteralExpression); case SyntaxKind.PropertyAccessExpression: return emitPropertyAccessExpression(node as PropertyAccessExpression); case SyntaxKind.ElementAccessExpression: @@ -2617,6 +2620,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri popNameGenerationScope(node); } + function emitEnumLiteralExpression(node: EnumLiteralExpression) { + writeSpace(); + writePunctuation("{"); + emitList(node, node.members, ListFormat.EnumMembers); + writePunctuation("}"); + } + function emitPropertyAccessExpression(node: PropertyAccessExpression) { emitExpression(node.expression, parenthesizer.parenthesizeLeftSideOfAccess); const token = node.questionDotToken || setTextRangePosEnd(factory.createToken(SyntaxKind.DotToken) as DotToken, node.expression.end, node.name.pos); diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 694262eeeb54a..26eec22ab331e 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -77,6 +77,7 @@ import { EndOfFileToken, EntityName, EnumDeclaration, + EnumLiteralExpression, EnumMember, EqualsGreaterThanToken, escapeLeadingUnderscores, @@ -160,6 +161,7 @@ import { isElementAccessChain, isElementAccessExpression, isEnumDeclaration, + isEnumLiteralExpression, isExclamationToken, isExportAssignment, isExportDeclaration, @@ -754,6 +756,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode updateTypeAliasDeclaration, createEnumDeclaration, updateEnumDeclaration, + createEnumLiteralExpression, + updateEnumLiteralExpression, createModuleDeclaration, updateModuleDeclaration, createModuleBlock, @@ -4539,6 +4543,39 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode : node; } + // @api + function createEnumLiteralExpression( + modifiers: readonly ModifierLike[] | undefined, + name: __String, + members: readonly EnumMember[], + ) { + const node = createBaseDeclaration(SyntaxKind.EnumLiteralExpression); + node.modifiers = asNodeArray(modifiers); + node.name = name; + node.members = createNodeArray(members); + node.transformFlags |= propagateChildrenFlags(node.modifiers) | + propagateChildrenFlags(node.members) | + TransformFlags.ContainsTypeScript; + node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Enum declarations cannot contain `await` + + node.jsDoc = undefined; // initialized by parser (JsDocContainer) + return node; + } + + // @api + function updateEnumLiteralExpression( + node: EnumLiteralExpression, + modifiers: readonly ModifierLike[] | undefined, + name: __String, + members: readonly EnumMember[], + ) { + return node.modifiers !== modifiers + || node.name !== name + || node.members !== members + ? update(createEnumLiteralExpression(modifiers, name, members), node) + : node; + } + // @api function createModuleDeclaration( modifiers: readonly ModifierLike[] | undefined, @@ -7086,6 +7123,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode isInterfaceDeclaration(node) ? updateInterfaceDeclaration(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members) : isTypeAliasDeclaration(node) ? updateTypeAliasDeclaration(node, modifierArray, node.name, node.typeParameters, node.type) : isEnumDeclaration(node) ? updateEnumDeclaration(node, modifierArray, node.name, node.members) : + isEnumLiteralExpression(node) ? updateEnumLiteralExpression(node, modifierArray, node.name, node.members) : isModuleDeclaration(node) ? updateModuleDeclaration(node, modifierArray, node.name, node.body) : isImportEqualsDeclaration(node) ? updateImportEqualsDeclaration(node, modifierArray, node.isTypeOnly, node.name, node.moduleReference) : isImportDeclaration(node) ? updateImportDeclaration(node, modifierArray, node.importClause, node.moduleSpecifier, node.attributes) : diff --git a/src/compiler/factory/nodeTests.ts b/src/compiler/factory/nodeTests.ts index 8aa4bb02e83d2..d82e0ef811975 100644 --- a/src/compiler/factory/nodeTests.ts +++ b/src/compiler/factory/nodeTests.ts @@ -47,6 +47,7 @@ import { ElementAccessExpression, EmptyStatement, EnumDeclaration, + EnumLiteralExpression, EnumMember, EqualsGreaterThanToken, ExclamationToken, @@ -817,6 +818,10 @@ export function isEnumDeclaration(node: Node): node is EnumDeclaration { return node.kind === SyntaxKind.EnumDeclaration; } +export function isEnumLiteralExpression(node: Node): node is EnumLiteralExpression { + return node.kind === SyntaxKind.EnumLiteralExpression; +} + export function isModuleDeclaration(node: Node): node is ModuleDeclaration { return node.kind === SyntaxKind.ModuleDeclaration; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 8c69cccba1282..a0c5622a17e67 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -75,6 +75,7 @@ import { ensureScriptKind, EntityName, EnumDeclaration, + EnumLiteralExpression, EnumMember, ExclamationToken, ExportAssignment, @@ -135,6 +136,7 @@ import { isAssignmentOperator, isAsyncModifier, isClassMemberModifier, + isEnumTypeReference, isExportAssignment, isExportDeclaration, isExportModifier, @@ -919,6 +921,12 @@ const forEachChildTable: ForEachChildTable = { return visitNode(cbNode, node.name) || visitNode(cbNode, node.initializer); }, + [SyntaxKind.EnumLiteralExpression]: function forEachChildInEnumLiteralExpression(node: EnumLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + // For EnumLiteralExpression, the name is not visited or emitted. It is a reference to the binding name of a Declaration for which + // the EnumLiteralExpression is an initializer, and is used to permit diagnostic code for EnumDeclarations to be used. + return visitNodes(cbNode, cbNodes, node.modifiers) || + visitNodes(cbNode, cbNodes, node.members); + }, [SyntaxKind.ModuleDeclaration]: function forEachChildInModuleDeclaration(node: ModuleDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { return visitNodes(cbNode, cbNodes, node.modifiers) || visitNode(cbNode, node.name) || @@ -7617,11 +7625,14 @@ namespace Parser { return parseBindingIdentifier(privateIdentifierDiagnosticMessage); } - function parseVariableDeclarationAllowExclamation() { - return parseVariableDeclaration(/*allowExclamation*/ true); + // function parseVariableDeclarationAllowExclamation(): VariableDeclaration { + // return parseVariableDeclaration(/*allowExclamation*/ true, /*allowEnumType*/ false); + // } + function parseVariableDeclarationAllowEnumDeclaration(): VariableDeclaration { + return parseVariableDeclaration(/*allowExclamation*/ true, /*allowEnumType*/ true); } - function parseVariableDeclaration(allowExclamation?: boolean): VariableDeclaration { + function parseVariableDeclaration(allowExclamation?: boolean, allowEnumType?: boolean): VariableDeclaration { const pos = getNodePos(); const hasJSDoc = hasPrecedingJSDocComment(); const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_are_not_allowed_in_variable_declarations); @@ -7633,6 +7644,12 @@ namespace Parser { exclamationToken = parseTokenNode>(); } const type = parseTypeAnnotation(); + if (allowEnumType && type && isEnumTypeReference(type) && name.kind === SyntaxKind.Identifier) { + const initializer = parseInitializerAsEnumLiteralExpression(name); + const node = factoryCreateVariableDeclaration(name, exclamationToken, type, initializer); + return withJSDoc(finishNode(node, pos), hasJSDoc); + } + const initializer = isInOrOfKeyword(token()) ? undefined : parseInitializer(); const node = factoryCreateVariableDeclaration(name, exclamationToken, type, initializer); return withJSDoc(finishNode(node, pos), hasJSDoc); @@ -7684,7 +7701,7 @@ namespace Parser { declarations = parseDelimitedList( ParsingContext.VariableDeclarations, - inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowExclamation, + inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowEnumDeclaration, ); setDisallowInContext(savedDisallowIn); @@ -8245,6 +8262,21 @@ namespace Parser { return withJSDoc(finishNode(factory.createEnumMember(name, initializer), pos), hasJSDoc); } + function parseObjectLiteralEnumMember(): EnumMember { + // const MyEnum: enum = { name: value } + const pos = getNodePos(); + const hasJSDoc = hasPrecedingJSDocComment(); + const name = parsePropertyName(); + let initializer: Expression | undefined; + + if (token() === SyntaxKind.ColonToken) { + parseExpected(SyntaxKind.ColonToken); + initializer = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)); + } + const node = withJSDoc(finishNode(factory.createEnumMember(name, initializer), pos), hasJSDoc); + return node; + } + function parseEnumDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): EnumDeclaration { parseExpected(SyntaxKind.EnumKeyword); const name = parseIdentifier(); @@ -8260,6 +8292,19 @@ namespace Parser { return withJSDoc(finishNode(node, pos), hasJSDoc); } + function parseInitializerAsEnumLiteralExpression(name: Identifier) { + // A VariableDeclaration with a declared type `enum` expects the initializer to be in a format like an ObjectLiteralExpression, + // with only constant keys and property assignments, which are treated as EnumMembers. + const pos = getNodePos(); + parseExpected(SyntaxKind.EqualsToken); + parseExpected(SyntaxKind.OpenBraceToken); + const members = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralEnumMember); + parseExpected(SyntaxKind.CloseBraceToken); + + // Should the variable have the jsdoc, or the enum literal, or both? + return finishNode(factory.createEnumLiteralExpression(/*modifiers*/ undefined, name.escapedText, members), pos); + } + function parseModuleBlock(): ModuleBlock { const pos = getNodePos(); let statements; diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 75656cf5aefab..47d6e38c5184d 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -33,6 +33,7 @@ import { EmitHint, EntityName, EnumDeclaration, + EnumLiteralExpression, EnumMember, ExportAssignment, ExportDeclaration, @@ -808,6 +809,10 @@ export function transformTypeScript(context: TransformationContext): Transformer // TypeScript enum declarations do not exist in ES6 and must be rewritten. return visitEnumDeclaration(node as EnumDeclaration); + case SyntaxKind.EnumLiteralExpression: + // EnumLiteralExpression is rewritten as an ObjectLiteralExpression + return visitEnumLiteralExpression(node as EnumLiteralExpression); + case SyntaxKind.VariableStatement: // TypeScript namespace exports for variable statements must be transformed. return visitVariableStatement(node as VariableStatement); @@ -1783,7 +1788,7 @@ export function transformTypeScript(context: TransformationContext): Transformer * * @param node The enum declaration node. */ - function shouldEmitEnumDeclaration(node: EnumDeclaration) { + function shouldEmitEnumDeclaration(node: EnumDeclaration | EnumLiteralExpression) { return !isEnumConst(node) || shouldPreserveConstEnums(compilerOptions); } @@ -1884,7 +1889,7 @@ export function transformTypeScript(context: TransformationContext): Transformer * * @param node The enum declaration node. */ - function transformEnumBody(node: EnumDeclaration, localName: Identifier): Block { + function transformEnumBody(node: EnumDeclaration | EnumLiteralExpression, localName: Identifier): Block { const savedCurrentNamespaceLocalName = currentNamespaceContainerName; currentNamespaceContainerName = localName; @@ -1940,6 +1945,28 @@ export function transformTypeScript(context: TransformationContext): Transformer ); } + function visitEnumLiteralExpression(node: EnumLiteralExpression): ObjectLiteralExpression { + const properties: readonly ObjectLiteralElementLike[] = node.members.map((member: EnumMember): ObjectLiteralElementLike => { + if (member.initializer) { + return factory.createPropertyAssignment(member.name, member.initializer); + } + else { + return factory.createShorthandPropertyAssignment(idText(member.name as Identifier)); + } + }); + + // return factory.updateEnumLiteralExpression( + // node, + // node.modifiers, + // node.name, + // visitNodes(node.members, getObjectLiteralElementVisitor(node), isObjectLiteralElementLike), + // ); + const objectLiteral = factory.createObjectLiteralExpression(properties, /*multiLine*/ true); + setOriginalNode(objectLiteral, node); + setParent(objectLiteral, node.parent); + return objectLiteral; + } + /** * Transforms the value of an enum member. * diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f6ca75a68e17d..1f11e1b7be599 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -305,6 +305,7 @@ export const enum SyntaxKind { MetaProperty, SyntheticExpression, SatisfiesExpression, + EnumLiteralExpression, // Misc TemplateSpan, @@ -1101,6 +1102,7 @@ export type HasChildren = | BindingElement | ArrayLiteralExpression | ObjectLiteralExpression + | EnumLiteralExpression | PropertyAccessExpression | ElementAccessExpression | CallExpression @@ -1240,6 +1242,7 @@ export type HasJSDoc = | NamedTupleMember | NamespaceExportDeclaration | ObjectLiteralExpression + | EnumLiteralExpression | ParameterDeclaration | ParenthesizedExpression | PropertyAccessExpression @@ -1376,6 +1379,7 @@ export type HasModifiers = | InterfaceDeclaration | TypeAliasDeclaration | EnumDeclaration + | EnumLiteralExpression | ModuleDeclaration | ImportEqualsDeclaration | ImportDeclaration @@ -1412,6 +1416,7 @@ export type IsContainer = | ClassDeclaration | EnumDeclaration | ObjectLiteralExpression + | EnumLiteralExpression | TypeLiteralNode | JSDocTypeLiteral | JsxAttributes @@ -1878,6 +1883,14 @@ export interface VariableDeclaration extends NamedDeclaration, JSDocContainer { readonly initializer?: Expression; // Optional initializer } +export interface EnumLiteralDeclaration extends VariableDeclaration { + readonly kind: SyntaxKind.VariableDeclaration; + readonly parent: VariableDeclarationList; + readonly name: BindingName; + readonly type: TypeReferenceNode; + readonly initializer: EnumLiteralExpression; +} + /** @internal */ export type InitializedVariableDeclaration = VariableDeclaration & { readonly initializer: Expression; }; @@ -3593,7 +3606,7 @@ export interface TypeAliasDeclaration extends DeclarationStatement, JSDocContain export interface EnumMember extends NamedDeclaration, JSDocContainer { readonly kind: SyntaxKind.EnumMember; - readonly parent: EnumDeclaration; + readonly parent: EnumDeclarationType; // This does include ComputedPropertyName, but the parser will give an error // if it parses a ComputedPropertyName in an EnumMember readonly name: PropertyName; @@ -3607,6 +3620,16 @@ export interface EnumDeclaration extends DeclarationStatement, JSDocContainer { readonly members: NodeArray; } +export interface EnumLiteralExpression extends PrimaryExpression, Declaration, JSDocContainer { + readonly kind: SyntaxKind.EnumLiteralExpression; + readonly parent: VariableDeclaration; + readonly modifiers?: NodeArray; + readonly name: __String; // For compatibility with EnumDeclaration -- however this must be equal to the BindingName in the VariableDeclaration. + readonly members: NodeArray; +} + +export type EnumDeclarationType = EnumDeclaration | EnumLiteralExpression; + export type ModuleName = | Identifier | StringLiteral; @@ -4513,6 +4536,7 @@ export interface JsonMinusNumericLiteral extends PrefixUnaryExpression { export type JsonObjectExpression = | ObjectLiteralExpression + | EnumLiteralExpression | ArrayLiteralExpression | JsonMinusNumericLiteral | NumericLiteral @@ -9009,6 +9033,8 @@ export interface NodeFactory { updateTypeAliasDeclaration(node: TypeAliasDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration; createEnumDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier, members: readonly EnumMember[]): EnumDeclaration; updateEnumDeclaration(node: EnumDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier, members: readonly EnumMember[]): EnumDeclaration; + createEnumLiteralExpression(modifiers: readonly ModifierLike[] | undefined, name: __String, members: readonly EnumMember[]): EnumLiteralExpression; + updateEnumLiteralExpression(node: EnumLiteralExpression, modifiers: readonly ModifierLike[] | undefined, name: __String, members: readonly EnumMember[]): EnumLiteralExpression; createModuleDeclaration(modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags?: NodeFlags): ModuleDeclaration; updateModuleDeclaration(node: ModuleDeclaration, modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined): ModuleDeclaration; createModuleBlock(statements: readonly Statement[]): ModuleBlock; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 5755369134d8a..f4d07aad6bc67 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -118,6 +118,7 @@ import { EntityNameExpression, EntityNameOrEntityNameExpression, EnumDeclaration, + EnumDeclarationType, EqualityComparer, equalOwnProperties, EqualsToken, @@ -275,6 +276,7 @@ import { isDecorator, isElementAccessExpression, isEnumDeclaration, + isEnumLiteralDeclaration, isEnumMember, isExportAssignment, isExportDeclaration, @@ -2583,7 +2585,7 @@ export function isJsonSourceFile(file: SourceFile): file is JsonSourceFile { } /** @internal */ -export function isEnumConst(node: EnumDeclaration): boolean { +export function isEnumConst(node: EnumDeclarationType): boolean { return !!(getCombinedModifierFlags(node) & ModifierFlags.Const); } @@ -5887,6 +5889,7 @@ export function getOperatorPrecedence(nodeKind: SyntaxKind, operatorKind: Syntax case SyntaxKind.StringLiteral: case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.EnumLiteralExpression: case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: case SyntaxKind.ClassExpression: @@ -6804,6 +6807,7 @@ export function getAllAccessorDeclarations(declarations: readonly Declaration[] export function getEffectiveTypeAnnotationNode(node: Node): TypeNode | undefined { if (!isInJSFile(node) && isFunctionDeclaration(node)) return undefined; if (isTypeAliasDeclaration(node)) return undefined; // has a .type, is not a type annotation + if (isEnumLiteralDeclaration(node)) return undefined; // has a type reference, but is not used as a hint about the meaning of the initializer. const type = (node as HasType).type; if (type || !isInJSFile(node)) return type; return isJSDocPropertyLikeTag(node) ? node.typeExpression && node.typeExpression.type : getJSDocType(node); diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 02623678a0cf0..75a80ecb88d8d 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -56,6 +56,7 @@ import { EntityName, entityNameToString, EnumDeclaration, + EnumLiteralDeclaration, every, ExportAssignment, ExportDeclaration, @@ -123,6 +124,7 @@ import { isClassStaticBlockDeclaration, isDecorator, isElementAccessExpression, + isEnumLiteralExpression, isExpandoPropertyDeclaration, isExportAssignment, isExportDeclaration, @@ -1426,6 +1428,19 @@ export function isConstTypeReference(node: Node): boolean { node.typeName.escapedText === "const" && !node.typeArguments; } +export function isEnumTypeReference(node: Node): boolean { + return isTypeReferenceNode(node) && isIdentifier(node.typeName) && + node.typeName.escapedText === "enum" && !node.typeArguments; +} +export function isEnumLiteralDeclaration(node: Node): node is EnumLiteralDeclaration { + return isVariableDeclaration(node) && hasType(node) && isEnumTypeReference(node.type!) && hasInitializer(node) && isEnumLiteralExpression(node.initializer!); +} + +export function isEnumTypeAnnotation(node: Node): boolean { + if (isIdentifier(node)) node = node.parent; + return isEnumTypeReference(node) && node.parent && isEnumLiteralDeclaration(node.parent); +} + export function skipPartiallyEmittedExpressions(node: Expression): Expression; export function skipPartiallyEmittedExpressions(node: Node): Node; export function skipPartiallyEmittedExpressions(node: Node) { @@ -2006,6 +2021,7 @@ function isLeftHandSideExpressionKind(kind: SyntaxKind): boolean { case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.ParenthesizedExpression: case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.EnumLiteralExpression: case SyntaxKind.ClassExpression: case SyntaxKind.FunctionExpression: case SyntaxKind.Identifier: @@ -2323,6 +2339,7 @@ function isDeclarationKind(kind: SyntaxKind) { || kind === SyntaxKind.ClassStaticBlockDeclaration || kind === SyntaxKind.Constructor || kind === SyntaxKind.EnumDeclaration + || kind === SyntaxKind.EnumLiteralExpression || kind === SyntaxKind.EnumMember || kind === SyntaxKind.ExportSpecifier || kind === SyntaxKind.FunctionDeclaration diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts index dbd49379e5750..157b83090a21c 100644 --- a/src/compiler/visitorPublic.ts +++ b/src/compiler/visitorPublic.ts @@ -1480,6 +1480,15 @@ const visitEachChildTable: VisitEachChildTable = { ); }, + [SyntaxKind.EnumLiteralExpression]: function visitEachChildOfEnumDeclaration(node, visitor, context, nodesVisitor, _tokenVisitor) { + return context.factory.updateEnumLiteralExpression( + node, + nodesVisitor(node.modifiers, visitor, isModifierLike), + node.name, + nodesVisitor(node.members, visitor, isEnumMember), + ); + }, + [SyntaxKind.ModuleDeclaration]: function visitEachChildOfModuleDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateModuleDeclaration( node, diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 2531c9ea0413d..512e4bbcbb664 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3903,130 +3903,131 @@ declare namespace ts { MetaProperty = 236, SyntheticExpression = 237, SatisfiesExpression = 238, - TemplateSpan = 239, - SemicolonClassElement = 240, - Block = 241, - EmptyStatement = 242, - VariableStatement = 243, - ExpressionStatement = 244, - IfStatement = 245, - DoStatement = 246, - WhileStatement = 247, - ForStatement = 248, - ForInStatement = 249, - ForOfStatement = 250, - ContinueStatement = 251, - BreakStatement = 252, - ReturnStatement = 253, - WithStatement = 254, - SwitchStatement = 255, - LabeledStatement = 256, - ThrowStatement = 257, - TryStatement = 258, - DebuggerStatement = 259, - VariableDeclaration = 260, - VariableDeclarationList = 261, - FunctionDeclaration = 262, - ClassDeclaration = 263, - InterfaceDeclaration = 264, - TypeAliasDeclaration = 265, - EnumDeclaration = 266, - ModuleDeclaration = 267, - ModuleBlock = 268, - CaseBlock = 269, - NamespaceExportDeclaration = 270, - ImportEqualsDeclaration = 271, - ImportDeclaration = 272, - ImportClause = 273, - NamespaceImport = 274, - NamedImports = 275, - ImportSpecifier = 276, - ExportAssignment = 277, - ExportDeclaration = 278, - NamedExports = 279, - NamespaceExport = 280, - ExportSpecifier = 281, - MissingDeclaration = 282, - ExternalModuleReference = 283, - JsxElement = 284, - JsxSelfClosingElement = 285, - JsxOpeningElement = 286, - JsxClosingElement = 287, - JsxFragment = 288, - JsxOpeningFragment = 289, - JsxClosingFragment = 290, - JsxAttribute = 291, - JsxAttributes = 292, - JsxSpreadAttribute = 293, - JsxExpression = 294, - JsxNamespacedName = 295, - CaseClause = 296, - DefaultClause = 297, - HeritageClause = 298, - CatchClause = 299, - ImportAttributes = 300, - ImportAttribute = 301, - /** @deprecated */ AssertClause = 300, - /** @deprecated */ AssertEntry = 301, - /** @deprecated */ ImportTypeAssertionContainer = 302, - PropertyAssignment = 303, - ShorthandPropertyAssignment = 304, - SpreadAssignment = 305, - EnumMember = 306, - SourceFile = 307, - Bundle = 308, - JSDocTypeExpression = 309, - JSDocNameReference = 310, - JSDocMemberName = 311, - JSDocAllType = 312, - JSDocUnknownType = 313, - JSDocNullableType = 314, - JSDocNonNullableType = 315, - JSDocOptionalType = 316, - JSDocFunctionType = 317, - JSDocVariadicType = 318, - JSDocNamepathType = 319, - JSDoc = 320, + EnumLiteralExpression = 239, + TemplateSpan = 240, + SemicolonClassElement = 241, + Block = 242, + EmptyStatement = 243, + VariableStatement = 244, + ExpressionStatement = 245, + IfStatement = 246, + DoStatement = 247, + WhileStatement = 248, + ForStatement = 249, + ForInStatement = 250, + ForOfStatement = 251, + ContinueStatement = 252, + BreakStatement = 253, + ReturnStatement = 254, + WithStatement = 255, + SwitchStatement = 256, + LabeledStatement = 257, + ThrowStatement = 258, + TryStatement = 259, + DebuggerStatement = 260, + VariableDeclaration = 261, + VariableDeclarationList = 262, + FunctionDeclaration = 263, + ClassDeclaration = 264, + InterfaceDeclaration = 265, + TypeAliasDeclaration = 266, + EnumDeclaration = 267, + ModuleDeclaration = 268, + ModuleBlock = 269, + CaseBlock = 270, + NamespaceExportDeclaration = 271, + ImportEqualsDeclaration = 272, + ImportDeclaration = 273, + ImportClause = 274, + NamespaceImport = 275, + NamedImports = 276, + ImportSpecifier = 277, + ExportAssignment = 278, + ExportDeclaration = 279, + NamedExports = 280, + NamespaceExport = 281, + ExportSpecifier = 282, + MissingDeclaration = 283, + ExternalModuleReference = 284, + JsxElement = 285, + JsxSelfClosingElement = 286, + JsxOpeningElement = 287, + JsxClosingElement = 288, + JsxFragment = 289, + JsxOpeningFragment = 290, + JsxClosingFragment = 291, + JsxAttribute = 292, + JsxAttributes = 293, + JsxSpreadAttribute = 294, + JsxExpression = 295, + JsxNamespacedName = 296, + CaseClause = 297, + DefaultClause = 298, + HeritageClause = 299, + CatchClause = 300, + ImportAttributes = 301, + ImportAttribute = 302, + /** @deprecated */ AssertClause = 301, + /** @deprecated */ AssertEntry = 302, + /** @deprecated */ ImportTypeAssertionContainer = 303, + PropertyAssignment = 304, + ShorthandPropertyAssignment = 305, + SpreadAssignment = 306, + EnumMember = 307, + SourceFile = 308, + Bundle = 309, + JSDocTypeExpression = 310, + JSDocNameReference = 311, + JSDocMemberName = 312, + JSDocAllType = 313, + JSDocUnknownType = 314, + JSDocNullableType = 315, + JSDocNonNullableType = 316, + JSDocOptionalType = 317, + JSDocFunctionType = 318, + JSDocVariadicType = 319, + JSDocNamepathType = 320, + JSDoc = 321, /** @deprecated Use SyntaxKind.JSDoc */ - JSDocComment = 320, - JSDocText = 321, - JSDocTypeLiteral = 322, - JSDocSignature = 323, - JSDocLink = 324, - JSDocLinkCode = 325, - JSDocLinkPlain = 326, - JSDocTag = 327, - JSDocAugmentsTag = 328, - JSDocImplementsTag = 329, - JSDocAuthorTag = 330, - JSDocDeprecatedTag = 331, - JSDocClassTag = 332, - JSDocPublicTag = 333, - JSDocPrivateTag = 334, - JSDocProtectedTag = 335, - JSDocReadonlyTag = 336, - JSDocOverrideTag = 337, - JSDocCallbackTag = 338, - JSDocOverloadTag = 339, - JSDocEnumTag = 340, - JSDocParameterTag = 341, - JSDocReturnTag = 342, - JSDocThisTag = 343, - JSDocTypeTag = 344, - JSDocTemplateTag = 345, - JSDocTypedefTag = 346, - JSDocSeeTag = 347, - JSDocPropertyTag = 348, - JSDocThrowsTag = 349, - JSDocSatisfiesTag = 350, - JSDocImportTag = 351, - SyntaxList = 352, - NotEmittedStatement = 353, - NotEmittedTypeElement = 354, - PartiallyEmittedExpression = 355, - CommaListExpression = 356, - SyntheticReferenceExpression = 357, - Count = 358, + JSDocComment = 321, + JSDocText = 322, + JSDocTypeLiteral = 323, + JSDocSignature = 324, + JSDocLink = 325, + JSDocLinkCode = 326, + JSDocLinkPlain = 327, + JSDocTag = 328, + JSDocAugmentsTag = 329, + JSDocImplementsTag = 330, + JSDocAuthorTag = 331, + JSDocDeprecatedTag = 332, + JSDocClassTag = 333, + JSDocPublicTag = 334, + JSDocPrivateTag = 335, + JSDocProtectedTag = 336, + JSDocReadonlyTag = 337, + JSDocOverrideTag = 338, + JSDocCallbackTag = 339, + JSDocOverloadTag = 340, + JSDocEnumTag = 341, + JSDocParameterTag = 342, + JSDocReturnTag = 343, + JSDocThisTag = 344, + JSDocTypeTag = 345, + JSDocTemplateTag = 346, + JSDocTypedefTag = 347, + JSDocSeeTag = 348, + JSDocPropertyTag = 349, + JSDocThrowsTag = 350, + JSDocSatisfiesTag = 351, + JSDocImportTag = 352, + SyntaxList = 353, + NotEmittedStatement = 354, + NotEmittedTypeElement = 355, + PartiallyEmittedExpression = 356, + CommaListExpression = 357, + SyntheticReferenceExpression = 358, + Count = 359, FirstAssignment = 64, LastAssignment = 79, FirstCompoundAssignment = 65, @@ -4051,13 +4052,13 @@ declare namespace ts { LastTemplateToken = 18, FirstBinaryOperator = 30, LastBinaryOperator = 79, - FirstStatement = 243, - LastStatement = 259, + FirstStatement = 244, + LastStatement = 260, FirstNode = 166, - FirstJSDocNode = 309, - LastJSDocNode = 351, - FirstJSDocTagNode = 327, - LastJSDocTagNode = 351, + FirstJSDocNode = 310, + LastJSDocNode = 352, + FirstJSDocTagNode = 328, + LastJSDocTagNode = 352, } type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ShebangTrivia | SyntaxKind.ConflictMarkerTrivia; type LiteralSyntaxKind = SyntaxKind.NumericLiteral | SyntaxKind.BigIntLiteral | SyntaxKind.StringLiteral | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral | SyntaxKind.NoSubstitutionTemplateLiteral; @@ -4361,6 +4362,7 @@ declare namespace ts { | NamedTupleMember | NamespaceExportDeclaration | ObjectLiteralExpression + | EnumLiteralExpression | ParameterDeclaration | ParenthesizedExpression | PropertyAccessExpression @@ -4385,7 +4387,7 @@ declare namespace ts { type HasInitializer = HasExpressionInitializer | ForStatement | ForInStatement | ForOfStatement | JsxAttribute; type HasExpressionInitializer = VariableDeclaration | ParameterDeclaration | BindingElement | PropertyDeclaration | PropertyAssignment | EnumMember; type HasDecorators = ParameterDeclaration | PropertyDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ClassExpression | ClassDeclaration; - type HasModifiers = TypeParameterDeclaration | ParameterDeclaration | ConstructorTypeNode | PropertySignature | PropertyDeclaration | MethodSignature | MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | IndexSignatureDeclaration | FunctionExpression | ArrowFunction | ClassExpression | VariableStatement | FunctionDeclaration | ClassDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | ImportDeclaration | ExportAssignment | ExportDeclaration; + type HasModifiers = TypeParameterDeclaration | ParameterDeclaration | ConstructorTypeNode | PropertySignature | PropertyDeclaration | MethodSignature | MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | IndexSignatureDeclaration | FunctionExpression | ArrowFunction | ClassExpression | VariableStatement | FunctionDeclaration | ClassDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumDeclaration | EnumLiteralExpression | ModuleDeclaration | ImportEqualsDeclaration | ImportDeclaration | ExportAssignment | ExportDeclaration; interface NodeArray extends ReadonlyArray, ReadonlyTextRange { readonly hasTrailingComma: boolean; } @@ -4527,6 +4529,13 @@ declare namespace ts { readonly type?: TypeNode; readonly initializer?: Expression; } + interface EnumLiteralDeclaration extends VariableDeclaration { + readonly kind: SyntaxKind.VariableDeclaration; + readonly parent: VariableDeclarationList; + readonly name: BindingName; + readonly type: TypeReferenceNode; + readonly initializer: EnumLiteralExpression; + } interface VariableDeclarationList extends Node { readonly kind: SyntaxKind.VariableDeclarationList; readonly parent: VariableStatement | ForStatement | ForOfStatement | ForInStatement; @@ -5438,7 +5447,7 @@ declare namespace ts { } interface EnumMember extends NamedDeclaration, JSDocContainer { readonly kind: SyntaxKind.EnumMember; - readonly parent: EnumDeclaration; + readonly parent: EnumDeclarationType; readonly name: PropertyName; readonly initializer?: Expression; } @@ -5448,6 +5457,14 @@ declare namespace ts { readonly name: Identifier; readonly members: NodeArray; } + interface EnumLiteralExpression extends PrimaryExpression, Declaration, JSDocContainer { + readonly kind: SyntaxKind.EnumLiteralExpression; + readonly parent: VariableDeclaration; + readonly modifiers?: NodeArray; + readonly name: __String; + readonly members: NodeArray; + } + type EnumDeclarationType = EnumDeclaration | EnumLiteralExpression; type ModuleName = Identifier | StringLiteral; type ModuleBody = NamespaceBody | JSDocNamespaceBody; interface ModuleDeclaration extends DeclarationStatement, JSDocContainer, LocalsContainer { @@ -5953,7 +5970,7 @@ declare namespace ts { readonly operator: SyntaxKind.MinusToken; readonly operand: NumericLiteral; } - type JsonObjectExpression = ObjectLiteralExpression | ArrayLiteralExpression | JsonMinusNumericLiteral | NumericLiteral | StringLiteral | BooleanLiteral | NullLiteral; + type JsonObjectExpression = ObjectLiteralExpression | EnumLiteralExpression | ArrayLiteralExpression | JsonMinusNumericLiteral | NumericLiteral | StringLiteral | BooleanLiteral | NullLiteral; interface JsonObjectExpressionStatement extends ExpressionStatement { readonly expression: JsonObjectExpression; } @@ -7701,6 +7718,8 @@ declare namespace ts { updateTypeAliasDeclaration(node: TypeAliasDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration; createEnumDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier, members: readonly EnumMember[]): EnumDeclaration; updateEnumDeclaration(node: EnumDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier, members: readonly EnumMember[]): EnumDeclaration; + createEnumLiteralExpression(modifiers: readonly ModifierLike[] | undefined, name: __String, members: readonly EnumMember[]): EnumLiteralExpression; + updateEnumLiteralExpression(node: EnumLiteralExpression, modifiers: readonly ModifierLike[] | undefined, name: __String, members: readonly EnumMember[]): EnumLiteralExpression; createModuleDeclaration(modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags?: NodeFlags): ModuleDeclaration; updateModuleDeclaration(node: ModuleDeclaration, modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined): ModuleDeclaration; createModuleBlock(statements: readonly Statement[]): ModuleBlock; @@ -8727,6 +8746,9 @@ declare namespace ts { function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain | NonNullChain; function isNullishCoalesce(node: Node): boolean; function isConstTypeReference(node: Node): boolean; + function isEnumTypeReference(node: Node): boolean; + function isEnumLiteralDeclaration(node: Node): node is EnumLiteralDeclaration; + function isEnumTypeAnnotation(node: Node): boolean; function skipPartiallyEmittedExpressions(node: Expression): Expression; function skipPartiallyEmittedExpressions(node: Node): Node; function isNonNullChain(node: Node): node is NonNullChain; @@ -9040,6 +9062,7 @@ declare namespace ts { function isInterfaceDeclaration(node: Node): node is InterfaceDeclaration; function isTypeAliasDeclaration(node: Node): node is TypeAliasDeclaration; function isEnumDeclaration(node: Node): node is EnumDeclaration; + function isEnumLiteralExpression(node: Node): node is EnumLiteralExpression; function isModuleDeclaration(node: Node): node is ModuleDeclaration; function isModuleBlock(node: Node): node is ModuleBlock; function isCaseBlock(node: Node): node is CaseBlock; diff --git a/tests/baselines/reference/enumLiteralBasics.errors.txt b/tests/baselines/reference/enumLiteralBasics.errors.txt new file mode 100644 index 0000000000000..d8c9fbfe01197 --- /dev/null +++ b/tests/baselines/reference/enumLiteralBasics.errors.txt @@ -0,0 +1,96 @@ +enumLiteralBasics.ts(6,5): error TS1061: Enum member must have initializer. +enumLiteralBasics.ts(7,5): error TS1061: Enum member must have initializer. +enumLiteralBasics.ts(22,1): error TS2322: Type 'E1.Flag' is not assignable to type 'E1.Int'. +enumLiteralBasics.ts(27,7): error TS2322: Type '"exists"' is not assignable to type 'E1'. +enumLiteralBasics.ts(29,7): error TS2322: Type '"string"' is not assignable to type 'E1'. +enumLiteralBasics.ts(39,33): error TS2345: Argument of type '"exists"' is not assignable to parameter of type 'E1'. +enumLiteralBasics.ts(44,32): error TS2345: Argument of type '"string"' is not assignable to parameter of type 'E1'. +enumLiteralBasics.ts(52,38): error TS2345: Argument of type '"exists"' is not assignable to parameter of type 'E1.Int'. +enumLiteralBasics.ts(54,38): error TS2345: Argument of type '4' is not assignable to parameter of type 'E1.Int'. +enumLiteralBasics.ts(56,38): error TS2345: Argument of type 'E1.String' is not assignable to parameter of type 'E1.Int'. +enumLiteralBasics.ts(57,7): error TS2322: Type 'E1.Int' is not assignable to type 'E1.Flag'. +enumLiteralBasics.ts(57,38): error TS2345: Argument of type '"string"' is not assignable to parameter of type 'E1.Int'. + + +==== enumLiteralBasics.ts (12 errors) ==== + // Enum without initializers have first member = 0 and successive members = N + 1 + + // Enum literal syntax does not implement auto-incrementing behaviour. + let ExistingShorthand = "exists"; + const E1: enum = { + NonexistingShorthand, // error -- EnumLiteralExpressions require explicit property definitions. + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS1061: Enum member must have initializer. + ExistingShorthand, // error -- EnumLiteralExpressions require explicit property definitions. + ~~~~~~~~~~~~~~~~~ +!!! error TS1061: Enum member must have initializer. + Int: 1, // ok + String: "string", // ok + Flag: 8, // ok + }; + + // Valid assignments + const nonexist: E1 = E1.NonexistingShorthand; // ok + const exist: E1 = E1.ExistingShorthand; // ok + const ival: E1 = E1.Int; // ok + const sval: E1 = E1.String; // ok + let p_int: E1.Int = E1.Int; // ok + const p_nonexist: E1.NonexistingShorthand = E1.NonexistingShorthand; // ok + const p_exist: E1.ExistingShorthand = E1.ExistingShorthand; // ok + const p_string: E1.String = E1.String; // ok + p_int = E1.Flag; // Type 'E1.Flag' is not assignable to type 'E1.Int'. + ~~~~~ +!!! error TS2322: Type 'E1.Flag' is not assignable to type 'E1.Int'. + p_int = E1.Int | E1.Flag; + + // Assigning values which are not part of the enum despite being present in the enum + const nonexist_bad: E1 = undefined; // error + const exist_bad: E1 = "exists"; // error + ~~~~~~~~~ +!!! error TS2322: Type '"exists"' is not assignable to type 'E1'. + const ival_good: E1 = 1; // ok -- TypeScript is permissive of this in enums, to permit things like bitwise combinations of enum values. + const sval_bad: E1 = "string"; // error + ~~~~~~~~ +!!! error TS2322: Type '"string"' is not assignable to type 'E1'. + + const ival_notpresent: E1 = 4; // ok -- TypeScript is permissive of this in enums, to permit things like bitwise combinations of enum values. + + function functest(value: E1) { + console.log(value); + return value; + } + + const nonexist_bad2: E1 = functest(undefined); // error + const exist_bad2: E1 = functest("exists"); // error + ~~~~~~~~ +!!! error TS2345: Argument of type '"exists"' is not assignable to parameter of type 'E1'. + const ival_good2: E1 = functest(1); // ok + const ival_good3: E1 = functest(4); // ok + const ival_good4: E1 = functest(E1.Int | E1.Flag); // ok + const sval_good2: E1 = functest(E1.String); + const sval_bad2: E1 = functest("string"); // error + ~~~~~~~~ +!!! error TS2345: Argument of type '"string"' is not assignable to parameter of type 'E1'. + + function functest2(value: E1.Int) { + console.log(value); + return value; + } + + const nonexist_bad3: E1.Int = functest2(undefined); + const exist_bad3: E1.Int = functest2("exists"); // error + ~~~~~~~~ +!!! error TS2345: Argument of type '"exists"' is not assignable to parameter of type 'E1.Int'. + const ival_good5: E1.Int = functest2(1); // ok + const ival_good6: E1.Int = functest2(4); // ok + ~ +!!! error TS2345: Argument of type '4' is not assignable to parameter of type 'E1.Int'. + const ival_good7: E1.Int = functest2(E1.Int | E1.Flag); // ok + const sval_good3: E1.Int = functest2(E1.String); + ~~~~~~~~~ +!!! error TS2345: Argument of type 'E1.String' is not assignable to parameter of type 'E1.Int'. + const sval_bad3: E1.Flag = functest2("string"); // error + ~~~~~~~~~ +!!! error TS2322: Type 'E1.Int' is not assignable to type 'E1.Flag'. + ~~~~~~~~ +!!! error TS2345: Argument of type '"string"' is not assignable to parameter of type 'E1.Int'. \ No newline at end of file diff --git a/tests/baselines/reference/enumLiteralBasics.js b/tests/baselines/reference/enumLiteralBasics.js new file mode 100644 index 0000000000000..746a45d16e91a --- /dev/null +++ b/tests/baselines/reference/enumLiteralBasics.js @@ -0,0 +1,111 @@ +//// [tests/cases/conformance/enums/enumLiteralBasics.ts] //// + +//// [enumLiteralBasics.ts] +// Enum without initializers have first member = 0 and successive members = N + 1 + +// Enum literal syntax does not implement auto-incrementing behaviour. +let ExistingShorthand = "exists"; +const E1: enum = { + NonexistingShorthand, // error -- EnumLiteralExpressions require explicit property definitions. + ExistingShorthand, // error -- EnumLiteralExpressions require explicit property definitions. + Int: 1, // ok + String: "string", // ok + Flag: 8, // ok +}; + +// Valid assignments +const nonexist: E1 = E1.NonexistingShorthand; // ok +const exist: E1 = E1.ExistingShorthand; // ok +const ival: E1 = E1.Int; // ok +const sval: E1 = E1.String; // ok +let p_int: E1.Int = E1.Int; // ok +const p_nonexist: E1.NonexistingShorthand = E1.NonexistingShorthand; // ok +const p_exist: E1.ExistingShorthand = E1.ExistingShorthand; // ok +const p_string: E1.String = E1.String; // ok +p_int = E1.Flag; // Type 'E1.Flag' is not assignable to type 'E1.Int'. +p_int = E1.Int | E1.Flag; + +// Assigning values which are not part of the enum despite being present in the enum +const nonexist_bad: E1 = undefined; // error +const exist_bad: E1 = "exists"; // error +const ival_good: E1 = 1; // ok -- TypeScript is permissive of this in enums, to permit things like bitwise combinations of enum values. +const sval_bad: E1 = "string"; // error + +const ival_notpresent: E1 = 4; // ok -- TypeScript is permissive of this in enums, to permit things like bitwise combinations of enum values. + +function functest(value: E1) { + console.log(value); + return value; +} + +const nonexist_bad2: E1 = functest(undefined); // error +const exist_bad2: E1 = functest("exists"); // error +const ival_good2: E1 = functest(1); // ok +const ival_good3: E1 = functest(4); // ok +const ival_good4: E1 = functest(E1.Int | E1.Flag); // ok +const sval_good2: E1 = functest(E1.String); +const sval_bad2: E1 = functest("string"); // error + +function functest2(value: E1.Int) { + console.log(value); + return value; +} + +const nonexist_bad3: E1.Int = functest2(undefined); +const exist_bad3: E1.Int = functest2("exists"); // error +const ival_good5: E1.Int = functest2(1); // ok +const ival_good6: E1.Int = functest2(4); // ok +const ival_good7: E1.Int = functest2(E1.Int | E1.Flag); // ok +const sval_good3: E1.Int = functest2(E1.String); +const sval_bad3: E1.Flag = functest2("string"); // error + +//// [enumLiteralBasics.js] +// Enum without initializers have first member = 0 and successive members = N + 1 +// Enum literal syntax does not implement auto-incrementing behaviour. +var ExistingShorthand = "exists"; +var E1 = { + NonexistingShorthand: NonexistingShorthand, + ExistingShorthand: ExistingShorthand, + Int: 1, + String: "string", + Flag: 8 +}; +// Valid assignments +var nonexist = E1.NonexistingShorthand; // ok +var exist = E1.ExistingShorthand; // ok +var ival = E1.Int; // ok +var sval = E1.String; // ok +var p_int = E1.Int; // ok +var p_nonexist = E1.NonexistingShorthand; // ok +var p_exist = E1.ExistingShorthand; // ok +var p_string = E1.String; // ok +p_int = E1.Flag; // Type 'E1.Flag' is not assignable to type 'E1.Int'. +p_int = E1.Int | E1.Flag; +// Assigning values which are not part of the enum despite being present in the enum +var nonexist_bad = undefined; // error +var exist_bad = "exists"; // error +var ival_good = 1; // ok -- TypeScript is permissive of this in enums, to permit things like bitwise combinations of enum values. +var sval_bad = "string"; // error +var ival_notpresent = 4; // ok -- TypeScript is permissive of this in enums, to permit things like bitwise combinations of enum values. +function functest(value) { + console.log(value); + return value; +} +var nonexist_bad2 = functest(undefined); // error +var exist_bad2 = functest("exists"); // error +var ival_good2 = functest(1); // ok +var ival_good3 = functest(4); // ok +var ival_good4 = functest(E1.Int | E1.Flag); // ok +var sval_good2 = functest(E1.String); +var sval_bad2 = functest("string"); // error +function functest2(value) { + console.log(value); + return value; +} +var nonexist_bad3 = functest2(undefined); +var exist_bad3 = functest2("exists"); // error +var ival_good5 = functest2(1); // ok +var ival_good6 = functest2(4); // ok +var ival_good7 = functest2(E1.Int | E1.Flag); // ok +var sval_good3 = functest2(E1.String); +var sval_bad3 = functest2("string"); // error diff --git a/tests/baselines/reference/enumLiteralBasics.symbols b/tests/baselines/reference/enumLiteralBasics.symbols new file mode 100644 index 0000000000000..55325c930e8b0 --- /dev/null +++ b/tests/baselines/reference/enumLiteralBasics.symbols @@ -0,0 +1,255 @@ +//// [tests/cases/conformance/enums/enumLiteralBasics.ts] //// + +=== enumLiteralBasics.ts === +// Enum without initializers have first member = 0 and successive members = N + 1 + +// Enum literal syntax does not implement auto-incrementing behaviour. +let ExistingShorthand = "exists"; +>ExistingShorthand : Symbol(ExistingShorthand, Decl(enumLiteralBasics.ts, 3, 3)) + +const E1: enum = { +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) + + NonexistingShorthand, // error -- EnumLiteralExpressions require explicit property definitions. +>NonexistingShorthand : Symbol(E1.NonexistingShorthand, Decl(enumLiteralBasics.ts, 4, 18)) + + ExistingShorthand, // error -- EnumLiteralExpressions require explicit property definitions. +>ExistingShorthand : Symbol(E1.ExistingShorthand, Decl(enumLiteralBasics.ts, 5, 25)) + + Int: 1, // ok +>Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) + + String: "string", // ok +>String : Symbol(E1.String, Decl(enumLiteralBasics.ts, 7, 11)) + + Flag: 8, // ok +>Flag : Symbol(E1.Flag, Decl(enumLiteralBasics.ts, 8, 21)) + +}; + +// Valid assignments +const nonexist: E1 = E1.NonexistingShorthand; // ok +>nonexist : Symbol(nonexist, Decl(enumLiteralBasics.ts, 13, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>E1.NonexistingShorthand : Symbol(E1.NonexistingShorthand, Decl(enumLiteralBasics.ts, 4, 18)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>NonexistingShorthand : Symbol(E1.NonexistingShorthand, Decl(enumLiteralBasics.ts, 4, 18)) + +const exist: E1 = E1.ExistingShorthand; // ok +>exist : Symbol(exist, Decl(enumLiteralBasics.ts, 14, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>E1.ExistingShorthand : Symbol(E1.ExistingShorthand, Decl(enumLiteralBasics.ts, 5, 25)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>ExistingShorthand : Symbol(E1.ExistingShorthand, Decl(enumLiteralBasics.ts, 5, 25)) + +const ival: E1 = E1.Int; // ok +>ival : Symbol(ival, Decl(enumLiteralBasics.ts, 15, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>E1.Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) + +const sval: E1 = E1.String; // ok +>sval : Symbol(sval, Decl(enumLiteralBasics.ts, 16, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>E1.String : Symbol(E1.String, Decl(enumLiteralBasics.ts, 7, 11)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>String : Symbol(E1.String, Decl(enumLiteralBasics.ts, 7, 11)) + +let p_int: E1.Int = E1.Int; // ok +>p_int : Symbol(p_int, Decl(enumLiteralBasics.ts, 17, 3)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) +>E1.Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) + +const p_nonexist: E1.NonexistingShorthand = E1.NonexistingShorthand; // ok +>p_nonexist : Symbol(p_nonexist, Decl(enumLiteralBasics.ts, 18, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>NonexistingShorthand : Symbol(E1.NonexistingShorthand, Decl(enumLiteralBasics.ts, 4, 18)) +>E1.NonexistingShorthand : Symbol(E1.NonexistingShorthand, Decl(enumLiteralBasics.ts, 4, 18)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>NonexistingShorthand : Symbol(E1.NonexistingShorthand, Decl(enumLiteralBasics.ts, 4, 18)) + +const p_exist: E1.ExistingShorthand = E1.ExistingShorthand; // ok +>p_exist : Symbol(p_exist, Decl(enumLiteralBasics.ts, 19, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>ExistingShorthand : Symbol(E1.ExistingShorthand, Decl(enumLiteralBasics.ts, 5, 25)) +>E1.ExistingShorthand : Symbol(E1.ExistingShorthand, Decl(enumLiteralBasics.ts, 5, 25)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>ExistingShorthand : Symbol(E1.ExistingShorthand, Decl(enumLiteralBasics.ts, 5, 25)) + +const p_string: E1.String = E1.String; // ok +>p_string : Symbol(p_string, Decl(enumLiteralBasics.ts, 20, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>String : Symbol(E1.String, Decl(enumLiteralBasics.ts, 7, 11)) +>E1.String : Symbol(E1.String, Decl(enumLiteralBasics.ts, 7, 11)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>String : Symbol(E1.String, Decl(enumLiteralBasics.ts, 7, 11)) + +p_int = E1.Flag; // Type 'E1.Flag' is not assignable to type 'E1.Int'. +>p_int : Symbol(p_int, Decl(enumLiteralBasics.ts, 17, 3)) +>E1.Flag : Symbol(E1.Flag, Decl(enumLiteralBasics.ts, 8, 21)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Flag : Symbol(E1.Flag, Decl(enumLiteralBasics.ts, 8, 21)) + +p_int = E1.Int | E1.Flag; +>p_int : Symbol(p_int, Decl(enumLiteralBasics.ts, 17, 3)) +>E1.Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) +>E1.Flag : Symbol(E1.Flag, Decl(enumLiteralBasics.ts, 8, 21)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Flag : Symbol(E1.Flag, Decl(enumLiteralBasics.ts, 8, 21)) + +// Assigning values which are not part of the enum despite being present in the enum +const nonexist_bad: E1 = undefined; // error +>nonexist_bad : Symbol(nonexist_bad, Decl(enumLiteralBasics.ts, 25, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>undefined : Symbol(undefined) + +const exist_bad: E1 = "exists"; // error +>exist_bad : Symbol(exist_bad, Decl(enumLiteralBasics.ts, 26, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) + +const ival_good: E1 = 1; // ok -- TypeScript is permissive of this in enums, to permit things like bitwise combinations of enum values. +>ival_good : Symbol(ival_good, Decl(enumLiteralBasics.ts, 27, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) + +const sval_bad: E1 = "string"; // error +>sval_bad : Symbol(sval_bad, Decl(enumLiteralBasics.ts, 28, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) + +const ival_notpresent: E1 = 4; // ok -- TypeScript is permissive of this in enums, to permit things like bitwise combinations of enum values. +>ival_notpresent : Symbol(ival_notpresent, Decl(enumLiteralBasics.ts, 30, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) + +function functest(value: E1) { +>functest : Symbol(functest, Decl(enumLiteralBasics.ts, 30, 30)) +>value : Symbol(value, Decl(enumLiteralBasics.ts, 32, 18)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) + + console.log(value); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>value : Symbol(value, Decl(enumLiteralBasics.ts, 32, 18)) + + return value; +>value : Symbol(value, Decl(enumLiteralBasics.ts, 32, 18)) +} + +const nonexist_bad2: E1 = functest(undefined); // error +>nonexist_bad2 : Symbol(nonexist_bad2, Decl(enumLiteralBasics.ts, 37, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>functest : Symbol(functest, Decl(enumLiteralBasics.ts, 30, 30)) +>undefined : Symbol(undefined) + +const exist_bad2: E1 = functest("exists"); // error +>exist_bad2 : Symbol(exist_bad2, Decl(enumLiteralBasics.ts, 38, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>functest : Symbol(functest, Decl(enumLiteralBasics.ts, 30, 30)) + +const ival_good2: E1 = functest(1); // ok +>ival_good2 : Symbol(ival_good2, Decl(enumLiteralBasics.ts, 39, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>functest : Symbol(functest, Decl(enumLiteralBasics.ts, 30, 30)) + +const ival_good3: E1 = functest(4); // ok +>ival_good3 : Symbol(ival_good3, Decl(enumLiteralBasics.ts, 40, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>functest : Symbol(functest, Decl(enumLiteralBasics.ts, 30, 30)) + +const ival_good4: E1 = functest(E1.Int | E1.Flag); // ok +>ival_good4 : Symbol(ival_good4, Decl(enumLiteralBasics.ts, 41, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>functest : Symbol(functest, Decl(enumLiteralBasics.ts, 30, 30)) +>E1.Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) +>E1.Flag : Symbol(E1.Flag, Decl(enumLiteralBasics.ts, 8, 21)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Flag : Symbol(E1.Flag, Decl(enumLiteralBasics.ts, 8, 21)) + +const sval_good2: E1 = functest(E1.String); +>sval_good2 : Symbol(sval_good2, Decl(enumLiteralBasics.ts, 42, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>functest : Symbol(functest, Decl(enumLiteralBasics.ts, 30, 30)) +>E1.String : Symbol(E1.String, Decl(enumLiteralBasics.ts, 7, 11)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>String : Symbol(E1.String, Decl(enumLiteralBasics.ts, 7, 11)) + +const sval_bad2: E1 = functest("string"); // error +>sval_bad2 : Symbol(sval_bad2, Decl(enumLiteralBasics.ts, 43, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>functest : Symbol(functest, Decl(enumLiteralBasics.ts, 30, 30)) + +function functest2(value: E1.Int) { +>functest2 : Symbol(functest2, Decl(enumLiteralBasics.ts, 43, 41)) +>value : Symbol(value, Decl(enumLiteralBasics.ts, 45, 19)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) + + console.log(value); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>value : Symbol(value, Decl(enumLiteralBasics.ts, 45, 19)) + + return value; +>value : Symbol(value, Decl(enumLiteralBasics.ts, 45, 19)) +} + +const nonexist_bad3: E1.Int = functest2(undefined); +>nonexist_bad3 : Symbol(nonexist_bad3, Decl(enumLiteralBasics.ts, 50, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) +>functest2 : Symbol(functest2, Decl(enumLiteralBasics.ts, 43, 41)) +>undefined : Symbol(undefined) + +const exist_bad3: E1.Int = functest2("exists"); // error +>exist_bad3 : Symbol(exist_bad3, Decl(enumLiteralBasics.ts, 51, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) +>functest2 : Symbol(functest2, Decl(enumLiteralBasics.ts, 43, 41)) + +const ival_good5: E1.Int = functest2(1); // ok +>ival_good5 : Symbol(ival_good5, Decl(enumLiteralBasics.ts, 52, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) +>functest2 : Symbol(functest2, Decl(enumLiteralBasics.ts, 43, 41)) + +const ival_good6: E1.Int = functest2(4); // ok +>ival_good6 : Symbol(ival_good6, Decl(enumLiteralBasics.ts, 53, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) +>functest2 : Symbol(functest2, Decl(enumLiteralBasics.ts, 43, 41)) + +const ival_good7: E1.Int = functest2(E1.Int | E1.Flag); // ok +>ival_good7 : Symbol(ival_good7, Decl(enumLiteralBasics.ts, 54, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) +>functest2 : Symbol(functest2, Decl(enumLiteralBasics.ts, 43, 41)) +>E1.Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) +>E1.Flag : Symbol(E1.Flag, Decl(enumLiteralBasics.ts, 8, 21)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Flag : Symbol(E1.Flag, Decl(enumLiteralBasics.ts, 8, 21)) + +const sval_good3: E1.Int = functest2(E1.String); +>sval_good3 : Symbol(sval_good3, Decl(enumLiteralBasics.ts, 55, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Int : Symbol(E1.Int, Decl(enumLiteralBasics.ts, 6, 22)) +>functest2 : Symbol(functest2, Decl(enumLiteralBasics.ts, 43, 41)) +>E1.String : Symbol(E1.String, Decl(enumLiteralBasics.ts, 7, 11)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>String : Symbol(E1.String, Decl(enumLiteralBasics.ts, 7, 11)) + +const sval_bad3: E1.Flag = functest2("string"); // error +>sval_bad3 : Symbol(sval_bad3, Decl(enumLiteralBasics.ts, 56, 5)) +>E1 : Symbol(E1, Decl(enumLiteralBasics.ts, 4, 5), Decl(enumLiteralBasics.ts, 4, 14)) +>Flag : Symbol(E1.Flag, Decl(enumLiteralBasics.ts, 8, 21)) +>functest2 : Symbol(functest2, Decl(enumLiteralBasics.ts, 43, 41)) + diff --git a/tests/baselines/reference/enumLiteralBasics.types b/tests/baselines/reference/enumLiteralBasics.types new file mode 100644 index 0000000000000..9048af49836d3 --- /dev/null +++ b/tests/baselines/reference/enumLiteralBasics.types @@ -0,0 +1,430 @@ +//// [tests/cases/conformance/enums/enumLiteralBasics.ts] //// + +=== enumLiteralBasics.ts === +// Enum without initializers have first member = 0 and successive members = N + 1 + +// Enum literal syntax does not implement auto-incrementing behaviour. +let ExistingShorthand = "exists"; +>ExistingShorthand : string +> : ^^^^^^ +>"exists" : "exists" +> : ^^^^^^^^ + +const E1: enum = { +>E1 : E1 +> : ^^ + + NonexistingShorthand, // error -- EnumLiteralExpressions require explicit property definitions. +>NonexistingShorthand : E1.NonexistingShorthand +> : ^^^^^^^^^^^^^^^^^^^^^^^ + + ExistingShorthand, // error -- EnumLiteralExpressions require explicit property definitions. +>ExistingShorthand : E1.ExistingShorthand +> : ^^^^^^^^^^^^^^^^^^^^ + + Int: 1, // ok +>Int : E1.Int +> : ^^^^^^ +>1 : 1 +> : ^ + + String: "string", // ok +>String : E1.String +> : ^^^^^^^^^ +>"string" : "string" +> : ^^^^^^^^ + + Flag: 8, // ok +>Flag : E1.Flag +> : ^^^^^^^ +>8 : 8 +> : ^ + +}; + +// Valid assignments +const nonexist: E1 = E1.NonexistingShorthand; // ok +>nonexist : E1 +> : ^^ +>E1.NonexistingShorthand : E1.NonexistingShorthand +> : ^^^^^^^^^^^^^^^^^^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>NonexistingShorthand : E1.NonexistingShorthand +> : ^^^^^^^^^^^^^^^^^^^^^^^ + +const exist: E1 = E1.ExistingShorthand; // ok +>exist : E1 +> : ^^ +>E1.ExistingShorthand : E1.ExistingShorthand +> : ^^^^^^^^^^^^^^^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>ExistingShorthand : E1.ExistingShorthand +> : ^^^^^^^^^^^^^^^^^^^^ + +const ival: E1 = E1.Int; // ok +>ival : E1 +> : ^^ +>E1.Int : E1.Int +> : ^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>Int : E1.Int +> : ^^^^^^ + +const sval: E1 = E1.String; // ok +>sval : E1 +> : ^^ +>E1.String : E1.String +> : ^^^^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>String : E1.String +> : ^^^^^^^^^ + +let p_int: E1.Int = E1.Int; // ok +>p_int : E1.Int +> : ^^^^^^ +>E1 : any +> : ^^^ +>E1.Int : E1.Int +> : ^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>Int : E1.Int +> : ^^^^^^ + +const p_nonexist: E1.NonexistingShorthand = E1.NonexistingShorthand; // ok +>p_nonexist : E1.NonexistingShorthand +> : ^^^^^^^^^^^^^^^^^^^^^^^ +>E1 : any +> : ^^^ +>E1.NonexistingShorthand : E1.NonexistingShorthand +> : ^^^^^^^^^^^^^^^^^^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>NonexistingShorthand : E1.NonexistingShorthand +> : ^^^^^^^^^^^^^^^^^^^^^^^ + +const p_exist: E1.ExistingShorthand = E1.ExistingShorthand; // ok +>p_exist : E1.ExistingShorthand +> : ^^^^^^^^^^^^^^^^^^^^ +>E1 : any +> : ^^^ +>E1.ExistingShorthand : E1.ExistingShorthand +> : ^^^^^^^^^^^^^^^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>ExistingShorthand : E1.ExistingShorthand +> : ^^^^^^^^^^^^^^^^^^^^ + +const p_string: E1.String = E1.String; // ok +>p_string : E1.String +> : ^^^^^^^^^ +>E1 : any +> : ^^^ +>E1.String : E1.String +> : ^^^^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>String : E1.String +> : ^^^^^^^^^ + +p_int = E1.Flag; // Type 'E1.Flag' is not assignable to type 'E1.Int'. +>p_int = E1.Flag : E1.Flag +> : ^^^^^^^ +>p_int : E1.Int +> : ^^^^^^ +>E1.Flag : E1.Flag +> : ^^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>Flag : E1.Flag +> : ^^^^^^^ + +p_int = E1.Int | E1.Flag; +>p_int = E1.Int | E1.Flag : number +> : ^^^^^^ +>p_int : E1.Int +> : ^^^^^^ +>E1.Int | E1.Flag : number +> : ^^^^^^ +>E1.Int : E1.Int +> : ^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>Int : E1.Int +> : ^^^^^^ +>E1.Flag : E1.Flag +> : ^^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>Flag : E1.Flag +> : ^^^^^^^ + +// Assigning values which are not part of the enum despite being present in the enum +const nonexist_bad: E1 = undefined; // error +>nonexist_bad : E1 +> : ^^ +>undefined : undefined +> : ^^^^^^^^^ + +const exist_bad: E1 = "exists"; // error +>exist_bad : E1 +> : ^^ +>"exists" : "exists" +> : ^^^^^^^^ + +const ival_good: E1 = 1; // ok -- TypeScript is permissive of this in enums, to permit things like bitwise combinations of enum values. +>ival_good : E1 +> : ^^ +>1 : 1 +> : ^ + +const sval_bad: E1 = "string"; // error +>sval_bad : E1 +> : ^^ +>"string" : "string" +> : ^^^^^^^^ + +const ival_notpresent: E1 = 4; // ok -- TypeScript is permissive of this in enums, to permit things like bitwise combinations of enum values. +>ival_notpresent : E1 +> : ^^ +>4 : 4 +> : ^ + +function functest(value: E1) { +>functest : (value: E1) => E1 +> : ^ ^^^^^^^^^^^ +>value : E1 +> : ^^ + + console.log(value); +>console.log(value) : void +> : ^^^^ +>console.log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>console : Console +> : ^^^^^^^ +>log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>value : E1 +> : ^^ + + return value; +>value : E1 +> : ^^ +} + +const nonexist_bad2: E1 = functest(undefined); // error +>nonexist_bad2 : E1 +> : ^^ +>functest(undefined) : E1 +> : ^^ +>functest : (value: E1) => E1 +> : ^ ^^^^^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ + +const exist_bad2: E1 = functest("exists"); // error +>exist_bad2 : E1 +> : ^^ +>functest("exists") : E1 +> : ^^ +>functest : (value: E1) => E1 +> : ^ ^^^^^^^^^^^ +>"exists" : "exists" +> : ^^^^^^^^ + +const ival_good2: E1 = functest(1); // ok +>ival_good2 : E1 +> : ^^ +>functest(1) : E1 +> : ^^ +>functest : (value: E1) => E1 +> : ^ ^^^^^^^^^^^ +>1 : 1 +> : ^ + +const ival_good3: E1 = functest(4); // ok +>ival_good3 : E1 +> : ^^ +>functest(4) : E1 +> : ^^ +>functest : (value: E1) => E1 +> : ^ ^^^^^^^^^^^ +>4 : 4 +> : ^ + +const ival_good4: E1 = functest(E1.Int | E1.Flag); // ok +>ival_good4 : E1 +> : ^^ +>functest(E1.Int | E1.Flag) : E1 +> : ^^ +>functest : (value: E1) => E1 +> : ^ ^^^^^^^^^^^ +>E1.Int | E1.Flag : number +> : ^^^^^^ +>E1.Int : E1.Int +> : ^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>Int : E1.Int +> : ^^^^^^ +>E1.Flag : E1.Flag +> : ^^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>Flag : E1.Flag +> : ^^^^^^^ + +const sval_good2: E1 = functest(E1.String); +>sval_good2 : E1 +> : ^^ +>functest(E1.String) : E1 +> : ^^ +>functest : (value: E1) => E1 +> : ^ ^^^^^^^^^^^ +>E1.String : E1.String +> : ^^^^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>String : E1.String +> : ^^^^^^^^^ + +const sval_bad2: E1 = functest("string"); // error +>sval_bad2 : E1 +> : ^^ +>functest("string") : E1 +> : ^^ +>functest : (value: E1) => E1 +> : ^ ^^^^^^^^^^^ +>"string" : "string" +> : ^^^^^^^^ + +function functest2(value: E1.Int) { +>functest2 : (value: E1.Int) => E1.Int +> : ^ ^^^^^^^^^^^^^^^^^^^ +>value : E1.Int +> : ^^^^^^ +>E1 : any +> : ^^^ + + console.log(value); +>console.log(value) : void +> : ^^^^ +>console.log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>console : Console +> : ^^^^^^^ +>log : (...data: any[]) => void +> : ^^^^ ^^ ^^^^^ +>value : E1.Int +> : ^^^^^^ + + return value; +>value : E1.Int +> : ^^^^^^ +} + +const nonexist_bad3: E1.Int = functest2(undefined); +>nonexist_bad3 : E1.Int +> : ^^^^^^ +>E1 : any +> : ^^^ +>functest2(undefined) : E1.Int +> : ^^^^^^ +>functest2 : (value: E1.Int) => E1.Int +> : ^ ^^^^^^^^^^^^^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ + +const exist_bad3: E1.Int = functest2("exists"); // error +>exist_bad3 : E1.Int +> : ^^^^^^ +>E1 : any +> : ^^^ +>functest2("exists") : E1.Int +> : ^^^^^^ +>functest2 : (value: E1.Int) => E1.Int +> : ^ ^^^^^^^^^^^^^^^^^^^ +>"exists" : "exists" +> : ^^^^^^^^ + +const ival_good5: E1.Int = functest2(1); // ok +>ival_good5 : E1.Int +> : ^^^^^^ +>E1 : any +> : ^^^ +>functest2(1) : E1.Int +> : ^^^^^^ +>functest2 : (value: E1.Int) => E1.Int +> : ^ ^^^^^^^^^^^^^^^^^^^ +>1 : 1 +> : ^ + +const ival_good6: E1.Int = functest2(4); // ok +>ival_good6 : E1.Int +> : ^^^^^^ +>E1 : any +> : ^^^ +>functest2(4) : E1.Int +> : ^^^^^^ +>functest2 : (value: E1.Int) => E1.Int +> : ^ ^^^^^^^^^^^^^^^^^^^ +>4 : 4 +> : ^ + +const ival_good7: E1.Int = functest2(E1.Int | E1.Flag); // ok +>ival_good7 : E1.Int +> : ^^^^^^ +>E1 : any +> : ^^^ +>functest2(E1.Int | E1.Flag) : E1.Int +> : ^^^^^^ +>functest2 : (value: E1.Int) => E1.Int +> : ^ ^^^^^^^^^^^^^^^^^^^ +>E1.Int | E1.Flag : number +> : ^^^^^^ +>E1.Int : E1.Int +> : ^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>Int : E1.Int +> : ^^^^^^ +>E1.Flag : E1.Flag +> : ^^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>Flag : E1.Flag +> : ^^^^^^^ + +const sval_good3: E1.Int = functest2(E1.String); +>sval_good3 : E1.Int +> : ^^^^^^ +>E1 : any +> : ^^^ +>functest2(E1.String) : E1.Int +> : ^^^^^^ +>functest2 : (value: E1.Int) => E1.Int +> : ^ ^^^^^^^^^^^^^^^^^^^ +>E1.String : E1.String +> : ^^^^^^^^^ +>E1 : typeof E1 +> : ^^^^^^^^^ +>String : E1.String +> : ^^^^^^^^^ + +const sval_bad3: E1.Flag = functest2("string"); // error +>sval_bad3 : E1.Flag +> : ^^^^^^^ +>E1 : any +> : ^^^ +>functest2("string") : E1.Int +> : ^^^^^^ +>functest2 : (value: E1.Int) => E1.Int +> : ^ ^^^^^^^^^^^^^^^^^^^ +>"string" : "string" +> : ^^^^^^^^ + diff --git a/tests/baselines/reference/enumLiteralSimple.js b/tests/baselines/reference/enumLiteralSimple.js new file mode 100644 index 0000000000000..5ddaa384269b5 --- /dev/null +++ b/tests/baselines/reference/enumLiteralSimple.js @@ -0,0 +1,16 @@ +//// [tests/cases/conformance/enums/enumLiteralSimple.ts] //// + +//// [enumLiteralSimple.ts] +const ENUM: enum = { + a: 1, + b: 2 +}; + +const a: ENUM = 1 + +//// [enumLiteralSimple.js] +var ENUM = { + a: 1, + b: 2 +}; +var a = 1; diff --git a/tests/baselines/reference/enumLiteralSimple.symbols b/tests/baselines/reference/enumLiteralSimple.symbols new file mode 100644 index 0000000000000..75a6792a56513 --- /dev/null +++ b/tests/baselines/reference/enumLiteralSimple.symbols @@ -0,0 +1,18 @@ +//// [tests/cases/conformance/enums/enumLiteralSimple.ts] //// + +=== enumLiteralSimple.ts === +const ENUM: enum = { +>ENUM : Symbol(ENUM, Decl(enumLiteralSimple.ts, 0, 5), Decl(enumLiteralSimple.ts, 0, 16)) + + a: 1, +>a : Symbol(ENUM.a, Decl(enumLiteralSimple.ts, 0, 20)) + + b: 2 +>b : Symbol(ENUM.b, Decl(enumLiteralSimple.ts, 1, 7)) + +}; + +const a: ENUM = 1 +>a : Symbol(a, Decl(enumLiteralSimple.ts, 5, 5)) +>ENUM : Symbol(ENUM, Decl(enumLiteralSimple.ts, 0, 5), Decl(enumLiteralSimple.ts, 0, 16)) + diff --git a/tests/baselines/reference/enumLiteralSimple.types b/tests/baselines/reference/enumLiteralSimple.types new file mode 100644 index 0000000000000..b33c8a58ffad3 --- /dev/null +++ b/tests/baselines/reference/enumLiteralSimple.types @@ -0,0 +1,27 @@ +//// [tests/cases/conformance/enums/enumLiteralSimple.ts] //// + +=== enumLiteralSimple.ts === +const ENUM: enum = { +>ENUM : ENUM +> : ^^^^ + + a: 1, +>a : ENUM.a +> : ^^^^^^ +>1 : 1 +> : ^ + + b: 2 +>b : ENUM.b +> : ^^^^^^ +>2 : 2 +> : ^ + +}; + +const a: ENUM = 1 +>a : ENUM +> : ^^^^ +>1 : 1 +> : ^ + diff --git a/tests/cases/conformance/enums/enumLiteralBasics.ts b/tests/cases/conformance/enums/enumLiteralBasics.ts new file mode 100644 index 0000000000000..dae3fab52127d --- /dev/null +++ b/tests/cases/conformance/enums/enumLiteralBasics.ts @@ -0,0 +1,57 @@ +// Enum without initializers have first member = 0 and successive members = N + 1 + +// Enum literal syntax does not implement auto-incrementing behaviour. +let ExistingShorthand = "exists"; +const E1: enum = { + NonexistingShorthand, // error -- EnumLiteralExpressions require explicit property definitions. + ExistingShorthand, // error -- EnumLiteralExpressions require explicit property definitions. + Int: 1, // ok + String: "string", // ok + Flag: 8, // ok +}; + +// Valid assignments +const nonexist: E1 = E1.NonexistingShorthand; // ok +const exist: E1 = E1.ExistingShorthand; // ok +const ival: E1 = E1.Int; // ok +const sval: E1 = E1.String; // ok +let p_int: E1.Int = E1.Int; // ok +const p_nonexist: E1.NonexistingShorthand = E1.NonexistingShorthand; // ok +const p_exist: E1.ExistingShorthand = E1.ExistingShorthand; // ok +const p_string: E1.String = E1.String; // ok +p_int = E1.Flag; // Type 'E1.Flag' is not assignable to type 'E1.Int'. +p_int = E1.Int | E1.Flag; + +// Assigning values which are not part of the enum despite being present in the enum +const nonexist_bad: E1 = undefined; // error +const exist_bad: E1 = "exists"; // error +const ival_good: E1 = 1; // ok -- TypeScript is permissive of this in enums, to permit things like bitwise combinations of enum values. +const sval_bad: E1 = "string"; // error + +const ival_notpresent: E1 = 4; // ok -- TypeScript is permissive of this in enums, to permit things like bitwise combinations of enum values. + +function functest(value: E1) { + console.log(value); + return value; +} + +const nonexist_bad2: E1 = functest(undefined); // error +const exist_bad2: E1 = functest("exists"); // error +const ival_good2: E1 = functest(1); // ok +const ival_good3: E1 = functest(4); // ok +const ival_good4: E1 = functest(E1.Int | E1.Flag); // ok +const sval_good2: E1 = functest(E1.String); +const sval_bad2: E1 = functest("string"); // error + +function functest2(value: E1.Int) { + console.log(value); + return value; +} + +const nonexist_bad3: E1.Int = functest2(undefined); +const exist_bad3: E1.Int = functest2("exists"); // error +const ival_good5: E1.Int = functest2(1); // ok +const ival_good6: E1.Int = functest2(4); // ok +const ival_good7: E1.Int = functest2(E1.Int | E1.Flag); // ok +const sval_good3: E1.Int = functest2(E1.String); +const sval_bad3: E1.Flag = functest2("string"); // error \ No newline at end of file diff --git a/tests/cases/conformance/enums/enumLiteralSimple.ts b/tests/cases/conformance/enums/enumLiteralSimple.ts new file mode 100644 index 0000000000000..cf52b22b27aad --- /dev/null +++ b/tests/cases/conformance/enums/enumLiteralSimple.ts @@ -0,0 +1,6 @@ +const ENUM: enum = { + a: 1, + b: 2 +}; + +const a: ENUM = 1 \ No newline at end of file