From fa0080f4802fd78fb0f01cd0160f299794d7843d Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 23 Sep 2024 11:09:06 -0700 Subject: [PATCH] Support interpreting non-literal computed properties in classes as implicit index signatures (#59860) --- src/compiler/checker.ts | 178 +++++++++++++++--- src/compiler/emitter.ts | 1 + src/compiler/transformers/declarations.ts | 4 +- src/compiler/types.ts | 3 +- .../reference/ES5SymbolProperty2.types | 8 +- .../reference/ES5SymbolProperty3.types | 3 +- .../reference/ES5SymbolProperty4.types | 3 +- .../reference/ES5SymbolProperty5.errors.txt | 13 ++ .../reference/ES5SymbolProperty5.types | 6 +- .../reference/ES5SymbolProperty6.types | 4 +- .../reference/ES5SymbolProperty7.types | 3 +- tests/baselines/reference/api/typescript.d.ts | 2 +- ...ssNonUniqueSymbolMethodHasSymbolIndexer.js | 39 ++++ ...UniqueSymbolMethodHasSymbolIndexer.symbols | 42 +++++ ...onUniqueSymbolMethodHasSymbolIndexer.types | 63 +++++++ .../reference/complicatedPrivacy.types | 4 +- .../computedPropertyNames12_ES5.errors.txt | 8 +- .../computedPropertyNames12_ES6.errors.txt | 8 +- ...clarationEmitAnyComputedPropertyInClass.js | 1 + ...arationEmitComputedPropertyNameEnum2.types | 4 +- .../parserComputedPropertyName13.types | 4 +- .../parserComputedPropertyName14.types | 4 +- .../parserComputedPropertyName18.types | 4 +- .../parserComputedPropertyName19.types | 4 +- .../parserES5ComputedPropertyName8.types | 4 +- .../reference/parserES5SymbolProperty8.types | 4 +- .../reference/parserES5SymbolProperty9.types | 4 +- .../reference/propertyAssignment.types | 8 +- .../reference/superSymbolIndexedAccess1.types | 10 +- .../reference/superSymbolIndexedAccess5.types | 10 +- .../reference/superSymbolIndexedAccess6.types | 10 +- .../declarationComputedPropertyNames.d.ts | 1 + ...ssNonUniqueSymbolMethodHasSymbolIndexer.ts | 15 ++ .../quickInfoInInvalidIndexSignature.ts | 2 +- 34 files changed, 400 insertions(+), 81 deletions(-) create mode 100644 tests/baselines/reference/ES5SymbolProperty5.errors.txt create mode 100644 tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.js create mode 100644 tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.symbols create mode 100644 tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.types create mode 100644 tests/cases/compiler/classNonUniqueSymbolMethodHasSymbolIndexer.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0caa731977623..e383e0de9574d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -583,6 +583,7 @@ import { isImportTypeNode, isInCompoundLikeAssignment, isIndexedAccessTypeNode, + isIndexSignatureDeclaration, isInExpressionContext, isInfinityOrNaNString, isInitializedProperty, @@ -878,6 +879,7 @@ import { ModuleResolutionKind, ModuleSpecifierResolutionHost, Mutable, + MutableNodeArray, NamedDeclaration, NamedExports, NamedImportsOrExports, @@ -13345,12 +13347,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * - The type of its expression is a string or numeric literal type, or is a `unique symbol` type. */ function isLateBindableName(node: DeclarationName): node is LateBoundName { + return isLateBindableAST(node) + && isTypeUsableAsPropertyName(isComputedPropertyName(node) ? checkComputedPropertyName(node) : checkExpressionCached((node as ElementAccessExpression).argumentExpression)); + } + + function isLateBindableIndexSignature(node: DeclarationName): node is LateBoundName { + return isLateBindableAST(node) + && isTypeUsableAsIndexSignature(isComputedPropertyName(node) ? checkComputedPropertyName(node) : checkExpressionCached((node as ElementAccessExpression).argumentExpression)); + } + + function isLateBindableAST(node: DeclarationName) { if (!isComputedPropertyName(node) && !isElementAccessExpression(node)) { return false; } const expr = isComputedPropertyName(node) ? node.expression : node.argumentExpression; - return isEntityNameExpression(expr) - && isTypeUsableAsPropertyName(isComputedPropertyName(node) ? checkComputedPropertyName(node) : checkExpressionCached(expr)); + return isEntityNameExpression(expr); + } + + function isTypeUsableAsIndexSignature(type: Type): boolean { + return isTypeAssignableTo(type, stringNumberSymbolType); } function isLateBoundName(name: __String): boolean { @@ -13367,6 +13382,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !!name && isLateBindableName(name); } + function hasLateBindableIndexSignature(node: Declaration) { + const name = getNameOfDeclaration(node); + return !!name && isLateBindableIndexSignature(name); + } + /** * Indicates whether a declaration has an early-bound name or a dynamic name that can be late-bound. */ @@ -13474,6 +13494,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return links.resolvedSymbol; } + function lateBindIndexSignature(parent: Symbol, earlySymbols: SymbolTable | undefined, lateSymbols: Map<__String, TransientSymbol>, decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration) { + // First, late bind the index symbol itself, if needed + let indexSymbol = lateSymbols.get(InternalSymbolName.Index); + if (!indexSymbol) { + const early = earlySymbols?.get(InternalSymbolName.Index); + if (!early) { + indexSymbol = createSymbol(SymbolFlags.None, InternalSymbolName.Index, CheckFlags.Late); + } + else { + indexSymbol = cloneSymbol(early); + indexSymbol.links.checkFlags |= CheckFlags.Late; + } + lateSymbols.set(InternalSymbolName.Index, indexSymbol); + } + // Then just add the computed name as a late bound declaration + // (note: unlike `addDeclarationToLateBoundSymbol` we do not set up a `.lateSymbol` on `decl`'s links, + // since that would point at an index symbol and not a single property symbol, like most consumers would expect) + if (!indexSymbol.declarations) { + indexSymbol.declarations = [decl]; + } + else if (!decl.symbol.isReplaceableByMethod) { + indexSymbol.declarations.push(decl); + } + } + function getResolvedMembersOrExportsOfSymbol(symbol: Symbol, resolutionKind: MembersOrExportsResolutionKind): Map<__String, Symbol> { const links = getSymbolLinks(symbol); if (!links[resolutionKind]) { @@ -13497,6 +13542,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (hasLateBindableName(member)) { lateBindMember(symbol, earlySymbols, lateSymbols, member); } + else if (hasLateBindableIndexSignature(member)) { + lateBindIndexSignature(symbol, earlySymbols, lateSymbols, member as Node as LateBoundDeclaration | LateBoundBinaryExpressionDeclaration); + } } } } @@ -14160,7 +14208,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const indexSymbol = getIndexSymbolFromSymbolTable(members); if (indexSymbol) { - indexInfos = getIndexInfosOfIndexSymbol(indexSymbol); + indexInfos = getIndexInfosOfIndexSymbol(indexSymbol, arrayFrom(members.values())); } else { if (baseConstructorIndexInfo) { @@ -16192,7 +16240,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getIndexSymbol(symbol: Symbol): Symbol | undefined { - return symbol.members ? getIndexSymbolFromSymbolTable(symbol.members) : undefined; + return symbol.members ? getIndexSymbolFromSymbolTable(getMembersOfSymbol(symbol)) : undefined; } function getIndexSymbolFromSymbolTable(symbolTable: SymbolTable): Symbol | undefined { @@ -16205,24 +16253,67 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getIndexInfosOfSymbol(symbol: Symbol): IndexInfo[] { const indexSymbol = getIndexSymbol(symbol); - return indexSymbol ? getIndexInfosOfIndexSymbol(indexSymbol) : emptyArray; + return indexSymbol ? getIndexInfosOfIndexSymbol(indexSymbol, arrayFrom(getMembersOfSymbol(symbol).values())) : emptyArray; } - function getIndexInfosOfIndexSymbol(indexSymbol: Symbol): IndexInfo[] { + // note intentional similarities to index signature building in `checkObjectLiteral` for parity + function getIndexInfosOfIndexSymbol(indexSymbol: Symbol, siblingSymbols: Symbol[] | undefined = indexSymbol.parent ? arrayFrom(getMembersOfSymbol(indexSymbol.parent).values()) : undefined): IndexInfo[] { if (indexSymbol.declarations) { const indexInfos: IndexInfo[] = []; - for (const declaration of (indexSymbol.declarations as IndexSignatureDeclaration[])) { - if (declaration.parameters.length === 1) { - const parameter = declaration.parameters[0]; - if (parameter.type) { - forEachType(getTypeFromTypeNode(parameter.type), keyType => { - if (isValidIndexKeyType(keyType) && !findIndexInfo(indexInfos, keyType)) { - indexInfos.push(createIndexInfo(keyType, declaration.type ? getTypeFromTypeNode(declaration.type) : anyType, hasEffectiveModifier(declaration, ModifierFlags.Readonly), declaration)); + let hasComputedNumberProperty = false; + let readonlyComputedNumberProperty = true; + let hasComputedSymbolProperty = false; + let readonlyComputedSymbolProperty = true; + let hasComputedStringProperty = false; + let readonlyComputedStringProperty = true; + const computedPropertySymbols: Symbol[] = []; + for (const declaration of indexSymbol.declarations) { + if (isIndexSignatureDeclaration(declaration)) { + if (declaration.parameters.length === 1) { + const parameter = declaration.parameters[0]; + if (parameter.type) { + forEachType(getTypeFromTypeNode(parameter.type), keyType => { + if (isValidIndexKeyType(keyType) && !findIndexInfo(indexInfos, keyType)) { + indexInfos.push(createIndexInfo(keyType, declaration.type ? getTypeFromTypeNode(declaration.type) : anyType, hasEffectiveModifier(declaration, ModifierFlags.Readonly), declaration)); + } + }); + } + } + } + else if (hasLateBindableIndexSignature(declaration)) { + const declName = isBinaryExpression(declaration) ? declaration.left as ElementAccessExpression : (declaration as LateBoundDeclaration).name; + const keyType = isElementAccessExpression(declName) ? checkExpressionCached(declName.argumentExpression) : checkComputedPropertyName(declName); + if (findIndexInfo(indexInfos, keyType)) { + continue; // Explicit index for key type takes priority + } + if (isTypeAssignableTo(keyType, stringNumberSymbolType)) { + if (isTypeAssignableTo(keyType, numberType)) { + hasComputedNumberProperty = true; + if (!hasEffectiveReadonlyModifier(declaration)) { + readonlyComputedNumberProperty = false; } - }); + } + else if (isTypeAssignableTo(keyType, esSymbolType)) { + hasComputedSymbolProperty = true; + if (!hasEffectiveReadonlyModifier(declaration)) { + readonlyComputedSymbolProperty = false; + } + } + else { + hasComputedStringProperty = true; + if (!hasEffectiveReadonlyModifier(declaration)) { + readonlyComputedStringProperty = false; + } + } + computedPropertySymbols.push(declaration.symbol); } } } + const allPropertySymbols = concatenate(computedPropertySymbols, filter(siblingSymbols, s => s !== indexSymbol)); + // aggregate similar index infos implied to be the same key to the same combined index info + if (hasComputedStringProperty && !findIndexInfo(indexInfos, stringType)) indexInfos.push(getObjectLiteralIndexInfo(readonlyComputedStringProperty, 0, allPropertySymbols, stringType)); + if (hasComputedNumberProperty && !findIndexInfo(indexInfos, numberType)) indexInfos.push(getObjectLiteralIndexInfo(readonlyComputedNumberProperty, 0, allPropertySymbols, numberType)); + if (hasComputedSymbolProperty && !findIndexInfo(indexInfos, esSymbolType)) indexInfos.push(getObjectLiteralIndexInfo(readonlyComputedSymbolProperty, 0, allPropertySymbols, esSymbolType)); return indexInfos; } return emptyArray; @@ -32790,7 +32881,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { isTypeAssignableToKind(checkComputedPropertyName(firstDecl.name), TypeFlags.ESSymbol)); } - function getObjectLiteralIndexInfo(node: ObjectLiteralExpression, offset: number, properties: Symbol[], keyType: Type): IndexInfo { + // NOTE: currently does not make pattern literal indexers, eg `${number}px` + function getObjectLiteralIndexInfo(isReadonly: boolean, offset: number, properties: Symbol[], keyType: Type): IndexInfo { const propTypes: Type[] = []; for (let i = offset; i < properties.length; i++) { const prop = properties[i]; @@ -32803,7 +32895,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } const unionType = propTypes.length ? getUnionType(propTypes, UnionReduction.Subtype) : undefinedType; - return createIndexInfo(keyType, unionType, isConstContext(node)); + return createIndexInfo(keyType, unionType, isReadonly); } function getImmediateAliasedSymbol(symbol: Symbol): Symbol | undefined { @@ -33008,9 +33100,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function createObjectLiteralType() { const indexInfos = []; - if (hasComputedStringProperty) indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, stringType)); - if (hasComputedNumberProperty) indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, numberType)); - if (hasComputedSymbolProperty) indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, esSymbolType)); + const isReadonly = isConstContext(node); + if (hasComputedStringProperty) indexInfos.push(getObjectLiteralIndexInfo(isReadonly, offset, propertiesArray, stringType)); + if (hasComputedNumberProperty) indexInfos.push(getObjectLiteralIndexInfo(isReadonly, offset, propertiesArray, numberType)); + if (hasComputedSymbolProperty) indexInfos.push(getObjectLiteralIndexInfo(isReadonly, offset, propertiesArray, esSymbolType)); const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, indexInfos); result.objectFlags |= objectFlags | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; if (isJSObjectLiteral) { @@ -41575,18 +41668,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const indexSymbol = getIndexSymbol(getSymbolOfDeclaration(node)); if (indexSymbol?.declarations) { const indexSignatureMap = new Map(); - for (const declaration of (indexSymbol.declarations as IndexSignatureDeclaration[])) { - if (declaration.parameters.length === 1 && declaration.parameters[0].type) { - forEachType(getTypeFromTypeNode(declaration.parameters[0].type), type => { - const entry = indexSignatureMap.get(getTypeId(type)); - if (entry) { - entry.declarations.push(declaration); - } - else { - indexSignatureMap.set(getTypeId(type), { type, declarations: [declaration] }); - } - }); + for (const declaration of indexSymbol.declarations) { + if (isIndexSignatureDeclaration(declaration)) { + if (declaration.parameters.length === 1 && declaration.parameters[0].type) { + forEachType(getTypeFromTypeNode(declaration.parameters[0].type), type => { + const entry = indexSignatureMap.get(getTypeId(type)); + if (entry) { + entry.declarations.push(declaration); + } + else { + indexSignatureMap.set(getTypeId(type), { type, declarations: [declaration] }); + } + }); + } } + // Do nothing for late-bound index signatures: allow these to duplicate one another and explicit indexes } indexSignatureMap.forEach(entry => { if (entry.declarations.length > 1) { @@ -50433,6 +50529,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }, isImportRequiredByAugmentation, isDefinitelyReferenceToGlobalSymbolObject, + createLateBoundIndexSignatures: (cls, enclosing, flags, internalFlags, tracker) => { + const sym = cls.symbol; + const staticInfos = getIndexInfosOfType(getTypeOfSymbol(sym)); + const instanceIndexSymbol = getIndexSymbol(sym); + const instanceInfos = instanceIndexSymbol && getIndexInfosOfIndexSymbol(instanceIndexSymbol, arrayFrom(getMembersOfSymbol(sym).values())); + let result; + for (const infoList of [staticInfos, instanceInfos]) { + if (!length(infoList)) continue; + result ||= []; + for (const info of infoList!) { + if (info.declaration) continue; + const node = nodeBuilder.indexInfoToIndexSignatureDeclaration(info, enclosing, flags, internalFlags, tracker); + if (node && infoList === staticInfos) { + (((node as Mutable).modifiers ||= factory.createNodeArray()) as MutableNodeArray).unshift(factory.createModifier(SyntaxKind.StaticKeyword)); + } + if (node) { + result.push(node); + } + } + } + return result; + }, }; function isImportRequiredByAugmentation(node: ImportDeclaration) { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 6b7c94fb84a2a..417ed4c2470f4 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1167,6 +1167,7 @@ export const notImplementedResolver: EmitResolver = { getDeclarationStatementsForSourceFile: notImplemented, isImportRequiredByAugmentation: notImplemented, isDefinitelyReferenceToGlobalSymbolObject: notImplemented, + createLateBoundIndexSignatures: notImplemented, }; const enum PipelinePhase { diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index ba19f34fe0af9..fa04121f7cc7a 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -12,6 +12,7 @@ import { canHaveModifiers, canProduceDiagnostics, ClassDeclaration, + ClassElement, compact, concatenate, ConditionalTypeNode, @@ -1652,7 +1653,8 @@ export function transformDeclarations(context: TransformationContext): Transform /*initializer*/ undefined, ), ] : undefined; - const memberNodes = concatenate(concatenate(privateIdentifier, parameterProperties), visitNodes(input.members, visitDeclarationSubtree, isClassElement)); + const lateIndexes = resolver.createLateBoundIndexSignatures(input, enclosingDeclaration, declarationEmitNodeBuilderFlags, declarationEmitInternalNodeBuilderFlags, symbolTracker); + const memberNodes = concatenate(concatenate(concatenate(privateIdentifier, lateIndexes), parameterProperties), visitNodes(input.members, visitDeclarationSubtree, isClassElement)); const members = factory.createNodeArray(memberNodes); const extendsClause = getEffectiveBaseTypeNode(input); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a0db02d050db1..93cd88ef2a3bd 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5048,7 +5048,7 @@ export interface TypeChecker { /** @internal */ getTypeOfPropertyOfType(type: Type, propertyName: string): Type | undefined; getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo | undefined; getIndexInfosOfType(type: Type): readonly IndexInfo[]; - getIndexInfosOfIndexSymbol: (indexSymbol: Symbol) => IndexInfo[]; + getIndexInfosOfIndexSymbol: (indexSymbol: Symbol, siblingSymbols?: Symbol[] | undefined) => IndexInfo[]; getSignaturesOfType(type: Type, kind: SignatureKind): readonly Signature[]; getIndexTypeOfType(type: Type, kind: IndexKind): Type | undefined; /** @internal */ getIndexType(type: Type): Type; @@ -5867,6 +5867,7 @@ export interface EmitResolver { getDeclarationStatementsForSourceFile(node: SourceFile, flags: NodeBuilderFlags, internalFlags: InternalNodeBuilderFlags, tracker: SymbolTracker): Statement[] | undefined; isImportRequiredByAugmentation(decl: ImportDeclaration): boolean; isDefinitelyReferenceToGlobalSymbolObject(node: Node): boolean; + createLateBoundIndexSignatures(cls: ClassLikeDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, internalFlags: InternalNodeBuilderFlags, tracker: SymbolTracker): IndexSignatureDeclaration[] | undefined; } // dprint-ignore diff --git a/tests/baselines/reference/ES5SymbolProperty2.types b/tests/baselines/reference/ES5SymbolProperty2.types index c3b8a051b1b0d..bb881741d6254 100644 --- a/tests/baselines/reference/ES5SymbolProperty2.types +++ b/tests/baselines/reference/ES5SymbolProperty2.types @@ -24,8 +24,8 @@ module M { > : ^^^ } (new C)[Symbol.iterator]; ->(new C)[Symbol.iterator] : any -> : ^^^ +>(new C)[Symbol.iterator] : () => void +> : ^^^^^^^^^^ >(new C) : C > : ^ >new C : C @@ -41,8 +41,8 @@ module M { } (new M.C)[Symbol.iterator]; ->(new M.C)[Symbol.iterator] : any -> : ^^^ +>(new M.C)[Symbol.iterator] : () => void +> : ^^^^^^^^^^ >(new M.C) : M.C > : ^^^ >new M.C : M.C diff --git a/tests/baselines/reference/ES5SymbolProperty3.types b/tests/baselines/reference/ES5SymbolProperty3.types index 406e96a719c2f..0a8427ac904eb 100644 --- a/tests/baselines/reference/ES5SymbolProperty3.types +++ b/tests/baselines/reference/ES5SymbolProperty3.types @@ -19,7 +19,8 @@ class C { } (new C)[Symbol.iterator] ->(new C)[Symbol.iterator] : error +>(new C)[Symbol.iterator] : () => void +> : ^^^^^^^^^^ >(new C) : C > : ^ >new C : C diff --git a/tests/baselines/reference/ES5SymbolProperty4.types b/tests/baselines/reference/ES5SymbolProperty4.types index 7b02ee9fa6eb0..f05889a1aa625 100644 --- a/tests/baselines/reference/ES5SymbolProperty4.types +++ b/tests/baselines/reference/ES5SymbolProperty4.types @@ -23,7 +23,8 @@ class C { } (new C)[Symbol.iterator] ->(new C)[Symbol.iterator] : error +>(new C)[Symbol.iterator] : () => void +> : ^^^^^^^^^^ >(new C) : C > : ^ >new C : C diff --git a/tests/baselines/reference/ES5SymbolProperty5.errors.txt b/tests/baselines/reference/ES5SymbolProperty5.errors.txt new file mode 100644 index 0000000000000..b16cf1a9e4507 --- /dev/null +++ b/tests/baselines/reference/ES5SymbolProperty5.errors.txt @@ -0,0 +1,13 @@ +ES5SymbolProperty5.ts(7,26): error TS2554: Expected 0 arguments, but got 1. + + +==== ES5SymbolProperty5.ts (1 errors) ==== + var Symbol: { iterator: symbol }; + + class C { + [Symbol.iterator]() { } + } + + (new C)[Symbol.iterator](0) // Should error + ~ +!!! error TS2554: Expected 0 arguments, but got 1. \ No newline at end of file diff --git a/tests/baselines/reference/ES5SymbolProperty5.types b/tests/baselines/reference/ES5SymbolProperty5.types index 1fba891c701c5..99ba0bd4f6e21 100644 --- a/tests/baselines/reference/ES5SymbolProperty5.types +++ b/tests/baselines/reference/ES5SymbolProperty5.types @@ -23,8 +23,10 @@ class C { } (new C)[Symbol.iterator](0) // Should error ->(new C)[Symbol.iterator](0) : error ->(new C)[Symbol.iterator] : error +>(new C)[Symbol.iterator](0) : void +> : ^^^^ +>(new C)[Symbol.iterator] : () => void +> : ^^^^^^^^^^ >(new C) : C > : ^ >new C : C diff --git a/tests/baselines/reference/ES5SymbolProperty6.types b/tests/baselines/reference/ES5SymbolProperty6.types index f4485046d83a1..7b2b3329ec082 100644 --- a/tests/baselines/reference/ES5SymbolProperty6.types +++ b/tests/baselines/reference/ES5SymbolProperty6.types @@ -17,8 +17,8 @@ class C { } (new C)[Symbol.iterator] ->(new C)[Symbol.iterator] : any -> : ^^^ +>(new C)[Symbol.iterator] : () => void +> : ^^^^^^^^^^ >(new C) : C > : ^ >new C : C diff --git a/tests/baselines/reference/ES5SymbolProperty7.types b/tests/baselines/reference/ES5SymbolProperty7.types index 324525e5ca3ca..15b9cc28809f0 100644 --- a/tests/baselines/reference/ES5SymbolProperty7.types +++ b/tests/baselines/reference/ES5SymbolProperty7.types @@ -21,7 +21,8 @@ class C { } (new C)[Symbol.iterator] ->(new C)[Symbol.iterator] : error +>(new C)[Symbol.iterator] : () => void +> : ^^^^^^^^^^ >(new C) : C > : ^ >new C : C diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 91bcbffd1ac5a..7b5d2f47a602c 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -6140,7 +6140,7 @@ declare namespace ts { getPrivateIdentifierPropertyOfType(leftType: Type, name: string, location: Node): Symbol | undefined; getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo | undefined; getIndexInfosOfType(type: Type): readonly IndexInfo[]; - getIndexInfosOfIndexSymbol: (indexSymbol: Symbol) => IndexInfo[]; + getIndexInfosOfIndexSymbol: (indexSymbol: Symbol, siblingSymbols?: Symbol[] | undefined) => IndexInfo[]; getSignaturesOfType(type: Type, kind: SignatureKind): readonly Signature[]; getIndexTypeOfType(type: Type, kind: IndexKind): Type | undefined; getBaseTypes(type: InterfaceType): BaseType[]; diff --git a/tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.js b/tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.js new file mode 100644 index 0000000000000..b62a61483a00d --- /dev/null +++ b/tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.js @@ -0,0 +1,39 @@ +//// [tests/cases/compiler/classNonUniqueSymbolMethodHasSymbolIndexer.ts] //// + +//// [classNonUniqueSymbolMethodHasSymbolIndexer.ts] +declare const a: symbol; +export class A { + [a]() { return 1 }; +} +declare const e1: A[typeof a]; // no error, `A` has `symbol` index + +type Constructor = new (...args: any[]) => {}; +declare function Mix(classish: T): T & (new (...args: any[]) => {mixed: true}); + +export const Mixer = Mix(class { + [a]() { return 1 }; +}); + + +//// [classNonUniqueSymbolMethodHasSymbolIndexer.js] +export class A { + [a]() { return 1; } + ; +} +export const Mixer = Mix(class { + [a]() { return 1; } + ; +}); + + +//// [classNonUniqueSymbolMethodHasSymbolIndexer.d.ts] +export declare class A { + [x: symbol]: () => number; +} +export declare const Mixer: { + new (): { + [x: symbol]: () => number; + }; +} & (new (...args: any[]) => { + mixed: true; +}); diff --git a/tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.symbols b/tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.symbols new file mode 100644 index 0000000000000..0c15a807cb4df --- /dev/null +++ b/tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.symbols @@ -0,0 +1,42 @@ +//// [tests/cases/compiler/classNonUniqueSymbolMethodHasSymbolIndexer.ts] //// + +=== classNonUniqueSymbolMethodHasSymbolIndexer.ts === +declare const a: symbol; +>a : Symbol(a, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 0, 13)) + +export class A { +>A : Symbol(A, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 0, 24)) + + [a]() { return 1 }; +>[a] : Symbol(A[a], Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 1, 16)) +>a : Symbol(a, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 0, 13)) +} +declare const e1: A[typeof a]; // no error, `A` has `symbol` index +>e1 : Symbol(e1, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 4, 13)) +>A : Symbol(A, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 0, 24)) +>a : Symbol(a, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 0, 13)) + +type Constructor = new (...args: any[]) => {}; +>Constructor : Symbol(Constructor, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 4, 30)) +>args : Symbol(args, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 6, 24)) + +declare function Mix(classish: T): T & (new (...args: any[]) => {mixed: true}); +>Mix : Symbol(Mix, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 6, 46)) +>T : Symbol(T, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 7, 21)) +>Constructor : Symbol(Constructor, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 4, 30)) +>classish : Symbol(classish, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 7, 44)) +>T : Symbol(T, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 7, 21)) +>T : Symbol(T, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 7, 21)) +>args : Symbol(args, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 7, 68)) +>mixed : Symbol(mixed, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 7, 88)) + +export const Mixer = Mix(class { +>Mixer : Symbol(Mixer, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 9, 12)) +>Mix : Symbol(Mix, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 6, 46)) + + [a]() { return 1 }; +>[a] : Symbol((Anonymous class)[a], Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 9, 32)) +>a : Symbol(a, Decl(classNonUniqueSymbolMethodHasSymbolIndexer.ts, 0, 13)) + +}); + diff --git a/tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.types b/tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.types new file mode 100644 index 0000000000000..96d2b1023ce4d --- /dev/null +++ b/tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.types @@ -0,0 +1,63 @@ +//// [tests/cases/compiler/classNonUniqueSymbolMethodHasSymbolIndexer.ts] //// + +=== classNonUniqueSymbolMethodHasSymbolIndexer.ts === +declare const a: symbol; +>a : symbol +> : ^^^^^^ + +export class A { +>A : A +> : ^ + + [a]() { return 1 }; +>[a] : () => number +> : ^^^^^^^^^^^^ +>a : symbol +> : ^^^^^^ +>1 : 1 +> : ^ +} +declare const e1: A[typeof a]; // no error, `A` has `symbol` index +>e1 : () => number +> : ^^^^^^^^^^^^ +>a : symbol +> : ^^^^^^ + +type Constructor = new (...args: any[]) => {}; +>Constructor : Constructor +> : ^^^^^^^^^^^ +>args : any[] +> : ^^^^^ + +declare function Mix(classish: T): T & (new (...args: any[]) => {mixed: true}); +>Mix : (classish: T) => T & (new (...args: any[]) => { mixed: true; }) +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ +>classish : T +> : ^ +>args : any[] +> : ^^^^^ +>mixed : true +> : ^^^^ +>true : true +> : ^^^^ + +export const Mixer = Mix(class { +>Mixer : typeof (Anonymous class) & (new (...args: any[]) => { mixed: true; }) +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^^^^ ^ +>Mix(class { [a]() { return 1 };}) : typeof (Anonymous class) & (new (...args: any[]) => { mixed: true; }) +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^^^^ ^ +>Mix : (classish: T) => T & (new (...args: any[]) => { mixed: true; }) +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ +>class { [a]() { return 1 };} : typeof (Anonymous class) +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + + [a]() { return 1 }; +>[a] : () => number +> : ^^^^^^^^^^^^ +>a : symbol +> : ^^^^^^ +>1 : 1 +> : ^ + +}); + diff --git a/tests/baselines/reference/complicatedPrivacy.types b/tests/baselines/reference/complicatedPrivacy.types index d9fd54eb04428..d0ff49fdceaa8 100644 --- a/tests/baselines/reference/complicatedPrivacy.types +++ b/tests/baselines/reference/complicatedPrivacy.types @@ -86,8 +86,8 @@ module m1 { export function f4(arg1: >f4 : (arg1: { [number]: C1; }) => void > : ^ ^^ ^^^^^^^^^ ->arg1 : {} -> : ^^ +>arg1 : { [x: number]: C1; } +> : ^^^^^^^^^^^^^^^^^^^^ { [number]: C1; // Used to be indexer, now it is a computed property >[number] : C1 diff --git a/tests/baselines/reference/computedPropertyNames12_ES5.errors.txt b/tests/baselines/reference/computedPropertyNames12_ES5.errors.txt index 1544788d8281d..54170d241bb85 100644 --- a/tests/baselines/reference/computedPropertyNames12_ES5.errors.txt +++ b/tests/baselines/reference/computedPropertyNames12_ES5.errors.txt @@ -3,12 +3,14 @@ computedPropertyNames12_ES5.ts(6,5): error TS1166: A computed property name in a computedPropertyNames12_ES5.ts(7,12): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. computedPropertyNames12_ES5.ts(8,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. computedPropertyNames12_ES5.ts(9,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. +computedPropertyNames12_ES5.ts(9,5): error TS2411: Property '[+s]' of type 'string' is not assignable to 'number' index type 'number'. +computedPropertyNames12_ES5.ts(9,5): error TS2411: Property '[+s]' of type 'string' is not assignable to 'string' index type 'number'. computedPropertyNames12_ES5.ts(12,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. computedPropertyNames12_ES5.ts(13,12): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. computedPropertyNames12_ES5.ts(15,12): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. -==== computedPropertyNames12_ES5.ts (8 errors) ==== +==== computedPropertyNames12_ES5.ts (10 errors) ==== var s: string; var n: number; var a: any; @@ -28,6 +30,10 @@ computedPropertyNames12_ES5.ts(15,12): error TS1166: A computed property name in [+s]: typeof s; ~~~~ !!! error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. + ~~~~ +!!! error TS2411: Property '[+s]' of type 'string' is not assignable to 'number' index type 'number'. + ~~~~ +!!! error TS2411: Property '[+s]' of type 'string' is not assignable to 'string' index type 'number'. static [""]: number; [0]: number; [a]: number; diff --git a/tests/baselines/reference/computedPropertyNames12_ES6.errors.txt b/tests/baselines/reference/computedPropertyNames12_ES6.errors.txt index e6566f930510e..045be616de457 100644 --- a/tests/baselines/reference/computedPropertyNames12_ES6.errors.txt +++ b/tests/baselines/reference/computedPropertyNames12_ES6.errors.txt @@ -3,12 +3,14 @@ computedPropertyNames12_ES6.ts(6,5): error TS1166: A computed property name in a computedPropertyNames12_ES6.ts(7,12): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. computedPropertyNames12_ES6.ts(8,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. computedPropertyNames12_ES6.ts(9,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. +computedPropertyNames12_ES6.ts(9,5): error TS2411: Property '[+s]' of type 'string' is not assignable to 'number' index type 'number'. +computedPropertyNames12_ES6.ts(9,5): error TS2411: Property '[+s]' of type 'string' is not assignable to 'string' index type 'number'. computedPropertyNames12_ES6.ts(12,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. computedPropertyNames12_ES6.ts(13,12): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. computedPropertyNames12_ES6.ts(15,12): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. -==== computedPropertyNames12_ES6.ts (8 errors) ==== +==== computedPropertyNames12_ES6.ts (10 errors) ==== var s: string; var n: number; var a: any; @@ -28,6 +30,10 @@ computedPropertyNames12_ES6.ts(15,12): error TS1166: A computed property name in [+s]: typeof s; ~~~~ !!! error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. + ~~~~ +!!! error TS2411: Property '[+s]' of type 'string' is not assignable to 'number' index type 'number'. + ~~~~ +!!! error TS2411: Property '[+s]' of type 'string' is not assignable to 'string' index type 'number'. static [""]: number; [0]: number; [a]: number; diff --git a/tests/baselines/reference/declarationEmitAnyComputedPropertyInClass.js b/tests/baselines/reference/declarationEmitAnyComputedPropertyInClass.js index c7d96ee96e0be..bc3473ad4d914 100644 --- a/tests/baselines/reference/declarationEmitAnyComputedPropertyInClass.js +++ b/tests/baselines/reference/declarationEmitAnyComputedPropertyInClass.js @@ -28,4 +28,5 @@ exports.C = C; //// [main.d.ts] export declare class C { + [x: number]: () => void; } diff --git a/tests/baselines/reference/declarationEmitComputedPropertyNameEnum2.types b/tests/baselines/reference/declarationEmitComputedPropertyNameEnum2.types index 1e5e4b1c668a0..d1e82f6148633 100644 --- a/tests/baselines/reference/declarationEmitComputedPropertyNameEnum2.types +++ b/tests/baselines/reference/declarationEmitComputedPropertyNameEnum2.types @@ -4,8 +4,8 @@ export type Type = { x?: { [Enum.A]: 0 } }; >Type : Type > : ^^^^ ->x : {} | undefined -> : ^^^^^^^^^^^^^^ +>x : { [x: number]: 0; } | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >[Enum.A] : 0 > : ^ >Enum.A : any diff --git a/tests/baselines/reference/parserComputedPropertyName13.types b/tests/baselines/reference/parserComputedPropertyName13.types index 6e99a4829fe25..0f33bd7c5f4a2 100644 --- a/tests/baselines/reference/parserComputedPropertyName13.types +++ b/tests/baselines/reference/parserComputedPropertyName13.types @@ -2,8 +2,8 @@ === parserComputedPropertyName13.ts === var v: { [e]: number }; ->v : {} -> : ^^ +>v : { [x: number]: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^ >[e] : number > : ^^^^^^ >e : any diff --git a/tests/baselines/reference/parserComputedPropertyName14.types b/tests/baselines/reference/parserComputedPropertyName14.types index 5678dc297079e..10fa63ce6fe05 100644 --- a/tests/baselines/reference/parserComputedPropertyName14.types +++ b/tests/baselines/reference/parserComputedPropertyName14.types @@ -2,8 +2,8 @@ === parserComputedPropertyName14.ts === var v: { [e](): number }; ->v : {} -> : ^^ +>v : { [x: number]: () => number; } +> : ^^^^^^^^^^^^^^^^^^^^^ ^^^ >[e] : () => number > : ^^^^^^ >e : any diff --git a/tests/baselines/reference/parserComputedPropertyName18.types b/tests/baselines/reference/parserComputedPropertyName18.types index 6cb139f89ae29..b4066ce95250b 100644 --- a/tests/baselines/reference/parserComputedPropertyName18.types +++ b/tests/baselines/reference/parserComputedPropertyName18.types @@ -2,8 +2,8 @@ === parserComputedPropertyName18.ts === var v: { [e]?(): number }; ->v : {} -> : ^^ +>v : { [x: number]: () => number; } +> : ^^^^^^^^^^^^^^^^^^^^^ ^^^ >[e] : () => number > : ^^^^^^ >e : any diff --git a/tests/baselines/reference/parserComputedPropertyName19.types b/tests/baselines/reference/parserComputedPropertyName19.types index 33ec268a9e308..ca0d674d53faf 100644 --- a/tests/baselines/reference/parserComputedPropertyName19.types +++ b/tests/baselines/reference/parserComputedPropertyName19.types @@ -2,8 +2,8 @@ === parserComputedPropertyName19.ts === var v: { [e]? }; ->v : {} -> : ^^ +>v : { [x: number]: any; } +> : ^^^^^^^^^^^^^^^^^^^^^ >[e] : any > : ^^^ >e : any diff --git a/tests/baselines/reference/parserES5ComputedPropertyName8.types b/tests/baselines/reference/parserES5ComputedPropertyName8.types index 15a66359e4b71..104894c313e2a 100644 --- a/tests/baselines/reference/parserES5ComputedPropertyName8.types +++ b/tests/baselines/reference/parserES5ComputedPropertyName8.types @@ -2,8 +2,8 @@ === parserES5ComputedPropertyName8.ts === var v: { [e]: number }; ->v : {} -> : ^^ +>v : { [x: number]: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^ >[e] : number > : ^^^^^^ >e : any diff --git a/tests/baselines/reference/parserES5SymbolProperty8.types b/tests/baselines/reference/parserES5SymbolProperty8.types index 1640d15ac08c8..ce13b98773f82 100644 --- a/tests/baselines/reference/parserES5SymbolProperty8.types +++ b/tests/baselines/reference/parserES5SymbolProperty8.types @@ -2,8 +2,8 @@ === parserES5SymbolProperty8.ts === var x: { ->x : {} -> : ^^ +>x : { [x: number]: () => string; } +> : ^^^^^^^^^^^^^^^^^^^^^ ^^^ [Symbol.toPrimitive](): string >[Symbol.toPrimitive] : () => string diff --git a/tests/baselines/reference/parserES5SymbolProperty9.types b/tests/baselines/reference/parserES5SymbolProperty9.types index d760467356cfa..1142830c03adb 100644 --- a/tests/baselines/reference/parserES5SymbolProperty9.types +++ b/tests/baselines/reference/parserES5SymbolProperty9.types @@ -2,8 +2,8 @@ === parserES5SymbolProperty9.ts === var x: { ->x : {} -> : ^^ +>x : { [x: number]: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^ [Symbol.toPrimitive]: string >[Symbol.toPrimitive] : string diff --git a/tests/baselines/reference/propertyAssignment.types b/tests/baselines/reference/propertyAssignment.types index c931d3d716091..f9f2a8bc55128 100644 --- a/tests/baselines/reference/propertyAssignment.types +++ b/tests/baselines/reference/propertyAssignment.types @@ -12,8 +12,8 @@ var bar1: { x : number; } > : ^^^^^^ var foo2: { [index]; } // should be an error, used to be indexer, now it is a computed property ->foo2 : {} -> : ^^ +>foo2 : { [x: number]: any; } +> : ^^^^^^^^^^^^^^^^^^^^^ >[index] : any > : ^^^ >index : any @@ -48,8 +48,8 @@ foo1 = bar1; // should be an error foo2 = bar2; >foo2 = bar2 : { x: number; } > : ^^^^^ ^^^ ->foo2 : {} -> : ^^ +>foo2 : { [x: number]: any; } +> : ^^^^^^^^^^^^^^^^^^^^^ >bar2 : { x: number; } > : ^^^^^ ^^^ diff --git a/tests/baselines/reference/superSymbolIndexedAccess1.types b/tests/baselines/reference/superSymbolIndexedAccess1.types index 122a3be1e875c..176a2b2cacfd4 100644 --- a/tests/baselines/reference/superSymbolIndexedAccess1.types +++ b/tests/baselines/reference/superSymbolIndexedAccess1.types @@ -38,14 +38,16 @@ class Bar extends Foo { > : ^^^ [symbol]() { ->[symbol] : () => any -> : ^^^^^^^^^ +>[symbol] : () => number +> : ^^^^^^^^^^^^ >symbol : symbol > : ^^^^^^ return super[symbol](); ->super[symbol]() : error ->super[symbol] : error +>super[symbol]() : number +> : ^^^^^^ +>super[symbol] : () => number +> : ^^^^^^^^^^^^ >super : Foo > : ^^^ >symbol : symbol diff --git a/tests/baselines/reference/superSymbolIndexedAccess5.types b/tests/baselines/reference/superSymbolIndexedAccess5.types index 0f4ba0f264fbb..26144f60740e4 100644 --- a/tests/baselines/reference/superSymbolIndexedAccess5.types +++ b/tests/baselines/reference/superSymbolIndexedAccess5.types @@ -26,13 +26,15 @@ class Bar extends Foo { > : ^^^ [symbol]() { ->[symbol] : () => any -> : ^^^^^^^^^ +>[symbol] : () => number +> : ^^^^^^^^^^^^ >symbol : any return super[symbol](); ->super[symbol]() : error ->super[symbol] : error +>super[symbol]() : number +> : ^^^^^^ +>super[symbol] : () => number +> : ^^^^^^^^^^^^ >super : Foo > : ^^^ >symbol : any diff --git a/tests/baselines/reference/superSymbolIndexedAccess6.types b/tests/baselines/reference/superSymbolIndexedAccess6.types index 619dbf1dabb1c..2c86a253d7f8c 100644 --- a/tests/baselines/reference/superSymbolIndexedAccess6.types +++ b/tests/baselines/reference/superSymbolIndexedAccess6.types @@ -26,13 +26,15 @@ class Bar extends Foo { > : ^^^ static [symbol]() { ->[symbol] : () => any -> : ^^^^^^^^^ +>[symbol] : () => number +> : ^^^^^^^^^^^^ >symbol : any return super[symbol](); ->super[symbol]() : error ->super[symbol] : error +>super[symbol]() : number +> : ^^^^^^ +>super[symbol] : () => number +> : ^^^^^^^^^^^^ >super : typeof Foo > : ^^^^^^^^^^ >symbol : any diff --git a/tests/baselines/reference/transpile/declarationComputedPropertyNames.d.ts b/tests/baselines/reference/transpile/declarationComputedPropertyNames.d.ts index 16e79cea6cedc..3c81cf66f0e84 100644 --- a/tests/baselines/reference/transpile/declarationComputedPropertyNames.d.ts +++ b/tests/baselines/reference/transpile/declarationComputedPropertyNames.d.ts @@ -86,6 +86,7 @@ export interface B { ["2"]: number; } export declare class C { + [x: number]: number; [Symbol.iterator]: number; [globalThis.Symbol.toStringTag]: number; [1]: number; diff --git a/tests/cases/compiler/classNonUniqueSymbolMethodHasSymbolIndexer.ts b/tests/cases/compiler/classNonUniqueSymbolMethodHasSymbolIndexer.ts new file mode 100644 index 0000000000000..ad6f24ee91a7a --- /dev/null +++ b/tests/cases/compiler/classNonUniqueSymbolMethodHasSymbolIndexer.ts @@ -0,0 +1,15 @@ +// @target: es6 +// @strict: true +// @declaration: true +declare const a: symbol; +export class A { + [a]() { return 1 }; +} +declare const e1: A[typeof a]; // no error, `A` has `symbol` index + +type Constructor = new (...args: any[]) => {}; +declare function Mix(classish: T): T & (new (...args: any[]) => {mixed: true}); + +export const Mixer = Mix(class { + [a]() { return 1 }; +}); diff --git a/tests/cases/fourslash/quickInfoInInvalidIndexSignature.ts b/tests/cases/fourslash/quickInfoInInvalidIndexSignature.ts index 8205da6a31e0b..4096153db6fc5 100644 --- a/tests/cases/fourslash/quickInfoInInvalidIndexSignature.ts +++ b/tests/cases/fourslash/quickInfoInInvalidIndexSignature.ts @@ -2,4 +2,4 @@ //// function method() { var /**/dictionary = <{ [index]: string; }>{}; } -verify.quickInfoAt("", "(local var) dictionary: {}"); +verify.quickInfoAt("", "(local var) dictionary: {\n [x: number]: string;\n}");