mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 03:09:39 -06:00
Support interpreting non-literal computed properties in classes as implicit index signatures (#59860)
This commit is contained in:
parent
e24cc01b08
commit
fa0080f480
@ -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<TypeId, { type: Type; declarations: IndexSignatureDeclaration[]; }>();
|
||||
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<typeof node>).modifiers ||= factory.createNodeArray()) as MutableNodeArray<Modifier>).unshift(factory.createModifier(SyntaxKind.StaticKeyword));
|
||||
}
|
||||
if (node) {
|
||||
result.push(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
};
|
||||
|
||||
function isImportRequiredByAugmentation(node: ImportDeclaration) {
|
||||
|
||||
@ -1167,6 +1167,7 @@ export const notImplementedResolver: EmitResolver = {
|
||||
getDeclarationStatementsForSourceFile: notImplemented,
|
||||
isImportRequiredByAugmentation: notImplemented,
|
||||
isDefinitelyReferenceToGlobalSymbolObject: notImplemented,
|
||||
createLateBoundIndexSignatures: notImplemented,
|
||||
};
|
||||
|
||||
const enum PipelinePhase {
|
||||
|
||||
@ -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<ClassElement>(privateIdentifier, lateIndexes), parameterProperties), visitNodes(input.members, visitDeclarationSubtree, isClassElement));
|
||||
const members = factory.createNodeArray(memberNodes);
|
||||
|
||||
const extendsClause = getEffectiveBaseTypeNode(input);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
13
tests/baselines/reference/ES5SymbolProperty5.errors.txt
Normal file
13
tests/baselines/reference/ES5SymbolProperty5.errors.txt
Normal file
@ -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.
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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[];
|
||||
|
||||
@ -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<T extends Constructor>(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;
|
||||
});
|
||||
@ -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<T extends Constructor>(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))
|
||||
|
||||
});
|
||||
|
||||
@ -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<T extends Constructor>(classish: T): T & (new (...args: any[]) => {mixed: true});
|
||||
>Mix : <T extends Constructor>(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 : <T extends Constructor>(classish: T) => T & (new (...args: any[]) => { mixed: true; })
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>class { [a]() { return 1 };} : typeof (Anonymous class)
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
[a]() { return 1 };
|
||||
>[a] : () => number
|
||||
> : ^^^^^^^^^^^^
|
||||
>a : symbol
|
||||
> : ^^^^^^
|
||||
>1 : 1
|
||||
> : ^
|
||||
|
||||
});
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -28,4 +28,5 @@ exports.C = C;
|
||||
|
||||
//// [main.d.ts]
|
||||
export declare class C {
|
||||
[x: number]: () => void;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
=== parserComputedPropertyName13.ts ===
|
||||
var v: { [e]: number };
|
||||
>v : {}
|
||||
> : ^^
|
||||
>v : { [x: number]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>[e] : number
|
||||
> : ^^^^^^
|
||||
>e : any
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
=== parserComputedPropertyName14.ts ===
|
||||
var v: { [e](): number };
|
||||
>v : {}
|
||||
> : ^^
|
||||
>v : { [x: number]: () => number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^ ^^^
|
||||
>[e] : () => number
|
||||
> : ^^^^^^
|
||||
>e : any
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
=== parserComputedPropertyName18.ts ===
|
||||
var v: { [e]?(): number };
|
||||
>v : {}
|
||||
> : ^^
|
||||
>v : { [x: number]: () => number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^ ^^^
|
||||
>[e] : () => number
|
||||
> : ^^^^^^
|
||||
>e : any
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
=== parserComputedPropertyName19.ts ===
|
||||
var v: { [e]? };
|
||||
>v : {}
|
||||
> : ^^
|
||||
>v : { [x: number]: any; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^
|
||||
>[e] : any
|
||||
> : ^^^
|
||||
>e : any
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
=== parserES5ComputedPropertyName8.ts ===
|
||||
var v: { [e]: number };
|
||||
>v : {}
|
||||
> : ^^
|
||||
>v : { [x: number]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>[e] : number
|
||||
> : ^^^^^^
|
||||
>e : any
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
=== parserES5SymbolProperty8.ts ===
|
||||
var x: {
|
||||
>x : {}
|
||||
> : ^^
|
||||
>x : { [x: number]: () => string; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^ ^^^
|
||||
|
||||
[Symbol.toPrimitive](): string
|
||||
>[Symbol.toPrimitive] : () => string
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
=== parserES5SymbolProperty9.ts ===
|
||||
var x: {
|
||||
>x : {}
|
||||
> : ^^
|
||||
>x : { [x: number]: string; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
[Symbol.toPrimitive]: string
|
||||
>[Symbol.toPrimitive] : string
|
||||
|
||||
@ -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; }
|
||||
> : ^^^^^ ^^^
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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<T extends Constructor>(classish: T): T & (new (...args: any[]) => {mixed: true});
|
||||
|
||||
export const Mixer = Mix(class {
|
||||
[a]() { return 1 };
|
||||
});
|
||||
@ -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}");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user