From 5c56b03fb90be61f517140f053ad6c0c5943bf60 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 4 Sep 2024 12:02:52 -0700 Subject: [PATCH 1/8] First draft of late bound index signature behavior --- src/compiler/checker.ts | 117 ++++++++++++++---- ...ssNonUniqueSymbolMethodHasSymbolIndexer.js | 38 ++++++ ...UniqueSymbolMethodHasSymbolIndexer.symbols | 42 +++++++ ...onUniqueSymbolMethodHasSymbolIndexer.types | 63 ++++++++++ ...ssNonUniqueSymbolMethodHasSymbolIndexer.ts | 15 +++ 5 files changed, 252 insertions(+), 23 deletions(-) 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 52e6862110f53..c6d9bd69acd70 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1121,6 +1121,7 @@ import { WideningContext, WithStatement, YieldExpression, + isIndexSignatureDeclaration, } from "./_namespaces/ts.js"; import * as moduleSpecifiers from "./_namespaces/ts.moduleSpecifiers.js"; import * as performance from "./_namespaces/ts.performance.js"; @@ -13344,12 +13345,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 { @@ -13366,6 +13380,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. */ @@ -13473,6 +13492,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]) { @@ -13496,6 +13540,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); + } } } } @@ -16191,7 +16238,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 { @@ -16210,17 +16257,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getIndexInfosOfIndexSymbol(indexSymbol: Symbol): 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)); - } - }); + 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)) { + // TODO: Combine index signatures inferred for each member? Or make an index info for each? + // Combined? + // Pros: Easily made, definite compatability with all relevant signatures. + // Cons: Unspecific. Can't make the signature until all declarations are processed + // Individual? + // Pros: Can inject one at a time. Accurate read types via index info applicability filtering. + // Cons: Can't tell at-a-glance which signatures apply? Potentially lots of signatures to track? + // Individual probably better, so is what we do here. + + const declName = isBinaryExpression(declaration) ? declaration.left as ElementAccessExpression : (declaration as LateBoundDeclaration).name; + const keyType = isElementAccessExpression(declName) ? checkExpressionCached(declName.argumentExpression) : checkComputedPropertyName(declName); + forEachType(keyType, keyType => { + // First-in-wins on multiple declarations right now - combine? leave as multiple, but with compatability error? + if (isValidIndexKeyType(keyType) && !findIndexInfo(indexInfos, keyType)) { + indexInfos.push(createIndexInfo(keyType, getTypeOfVariableOrParameterOrProperty(declaration.symbol), hasEffectiveModifier(declaration, ModifierFlags.Readonly))); + } + }); + } } return indexInfos; } @@ -41566,18 +41634,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) { diff --git a/tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.js b/tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.js new file mode 100644 index 0000000000000..e52b25c702203 --- /dev/null +++ b/tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.js @@ -0,0 +1,38 @@ +//// [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 { +} +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/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 }; +}); From 3342ff7105086ead2a370cb899cc503c6553c499 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 4 Sep 2024 15:26:45 -0700 Subject: [PATCH 2/8] Accept improved baselines --- .../reference/ES5SymbolProperty4.types | 3 ++- .../reference/ES5SymbolProperty5.errors.txt | 13 ++++++++++++ .../reference/ES5SymbolProperty5.types | 6 ++++-- ...pturedParametersInInitializers2.errors.txt | 5 ++++- .../computedPropertyNames12_ES5.errors.txt | 8 +++++++- .../computedPropertyNames12_ES6.errors.txt | 8 +++++++- .../computedPropertyNames2_ES5.errors.txt | 5 ++++- .../computedPropertyNames2_ES6.errors.txt | 5 ++++- ...PropertyNamesWithStaticProperty.errors.txt | 8 +++++++- ...solatedDeclarationErrorsClasses.errors.txt | 20 ++++++++++++++++++- .../reference/superSymbolIndexedAccess1.types | 10 ++++++---- 11 files changed, 77 insertions(+), 14 deletions(-) create mode 100644 tests/baselines/reference/ES5SymbolProperty5.errors.txt 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/capturedParametersInInitializers2.errors.txt b/tests/baselines/reference/capturedParametersInInitializers2.errors.txt index 7f7e502bfbba2..c190ffe48f335 100644 --- a/tests/baselines/reference/capturedParametersInInitializers2.errors.txt +++ b/tests/baselines/reference/capturedParametersInInitializers2.errors.txt @@ -1,11 +1,12 @@ capturedParametersInInitializers2.ts(3,20): error TS2373: Parameter 'y' cannot reference identifier 'x' declared after it. capturedParametersInInitializers2.ts(4,14): error TS2373: Parameter 'y' cannot reference identifier 'x' declared after it. +capturedParametersInInitializers2.ts(6,9): error TS2411: Property '[z]' of type '() => number' is not assignable to 'number' index type 'number'. capturedParametersInInitializers2.ts(6,10): error TS2373: Parameter 'y' cannot reference identifier 'z' declared after it. capturedParametersInInitializers2.ts(13,26): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. capturedParametersInInitializers2.ts(13,27): error TS2373: Parameter 'y' cannot reference identifier 'x' declared after it. -==== capturedParametersInInitializers2.ts (5 errors) ==== +==== capturedParametersInInitializers2.ts (6 errors) ==== function foo( y = class { static c = x; @@ -16,6 +17,8 @@ capturedParametersInInitializers2.ts(13,27): error TS2373: Parameter 'y' cannot !!! error TS2373: Parameter 'y' cannot reference identifier 'x' declared after it. constructor() { x; } [z]() { return z; } + ~~~ +!!! error TS2411: Property '[z]' of type '() => number' is not assignable to 'number' index type 'number'. ~ !!! error TS2373: Parameter 'y' cannot reference identifier 'z' declared after it. }, 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/computedPropertyNames2_ES5.errors.txt b/tests/baselines/reference/computedPropertyNames2_ES5.errors.txt index 2d1b4f1abc814..7f438a78ae85f 100644 --- a/tests/baselines/reference/computedPropertyNames2_ES5.errors.txt +++ b/tests/baselines/reference/computedPropertyNames2_ES5.errors.txt @@ -1,8 +1,9 @@ computedPropertyNames2_ES5.ts(6,9): error TS2378: A 'get' accessor must return a value. +computedPropertyNames2_ES5.ts(6,9): error TS2411: Property '[accessorName]' of type 'void' is not assignable to 'string' index type '() => void'. computedPropertyNames2_ES5.ts(8,16): error TS2378: A 'get' accessor must return a value. -==== computedPropertyNames2_ES5.ts (2 errors) ==== +==== computedPropertyNames2_ES5.ts (3 errors) ==== var methodName = "method"; var accessorName = "accessor"; class C { @@ -11,6 +12,8 @@ computedPropertyNames2_ES5.ts(8,16): error TS2378: A 'get' accessor must return get [accessorName]() { } ~~~~~~~~~~~~~~ !!! error TS2378: A 'get' accessor must return a value. + ~~~~~~~~~~~~~~ +!!! error TS2411: Property '[accessorName]' of type 'void' is not assignable to 'string' index type '() => void'. set [accessorName](v) { } static get [accessorName]() { } ~~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/computedPropertyNames2_ES6.errors.txt b/tests/baselines/reference/computedPropertyNames2_ES6.errors.txt index e9f4abaf8f56a..bdf812aaf93d7 100644 --- a/tests/baselines/reference/computedPropertyNames2_ES6.errors.txt +++ b/tests/baselines/reference/computedPropertyNames2_ES6.errors.txt @@ -1,8 +1,9 @@ computedPropertyNames2_ES6.ts(6,9): error TS2378: A 'get' accessor must return a value. +computedPropertyNames2_ES6.ts(6,9): error TS2411: Property '[accessorName]' of type 'void' is not assignable to 'string' index type '() => void'. computedPropertyNames2_ES6.ts(8,16): error TS2378: A 'get' accessor must return a value. -==== computedPropertyNames2_ES6.ts (2 errors) ==== +==== computedPropertyNames2_ES6.ts (3 errors) ==== var methodName = "method"; var accessorName = "accessor"; class C { @@ -11,6 +12,8 @@ computedPropertyNames2_ES6.ts(8,16): error TS2378: A 'get' accessor must return get [accessorName]() { } ~~~~~~~~~~~~~~ !!! error TS2378: A 'get' accessor must return a value. + ~~~~~~~~~~~~~~ +!!! error TS2411: Property '[accessorName]' of type 'void' is not assignable to 'string' index type '() => void'. set [accessorName](v) { } static get [accessorName]() { } ~~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/computedPropertyNamesWithStaticProperty.errors.txt b/tests/baselines/reference/computedPropertyNamesWithStaticProperty.errors.txt index 466c66649665c..5e36265fb4766 100644 --- a/tests/baselines/reference/computedPropertyNamesWithStaticProperty.errors.txt +++ b/tests/baselines/reference/computedPropertyNamesWithStaticProperty.errors.txt @@ -1,12 +1,14 @@ computedPropertyNamesWithStaticProperty.ts(3,10): error TS2449: Class 'C1' used before its declaration. computedPropertyNamesWithStaticProperty.ts(6,10): error TS2449: Class 'C1' used before its declaration. +computedPropertyNamesWithStaticProperty.ts(9,5): error TS2411: Property '[C1.staticProp]' of type '() => void' is not assignable to 'number' index type 'string'. computedPropertyNamesWithStaticProperty.ts(9,6): error TS2449: Class 'C1' used before its declaration. computedPropertyNamesWithStaticProperty.ts(14,10): error TS2449: Class 'C2' used before its declaration. computedPropertyNamesWithStaticProperty.ts(17,10): error TS2449: Class 'C2' used before its declaration. +computedPropertyNamesWithStaticProperty.ts(20,5): error TS2411: Property '[C2.staticProp]' of type '() => void' is not assignable to 'number' index type 'string'. computedPropertyNamesWithStaticProperty.ts(20,6): error TS2449: Class 'C2' used before its declaration. -==== computedPropertyNamesWithStaticProperty.ts (6 errors) ==== +==== computedPropertyNamesWithStaticProperty.ts (8 errors) ==== class C1 { static staticProp = 10; get [C1.staticProp]() { @@ -22,6 +24,8 @@ computedPropertyNamesWithStaticProperty.ts(20,6): error TS2449: Class 'C2' used var y = x; } [C1.staticProp]() { } + ~~~~~~~~~~~~~~~ +!!! error TS2411: Property '[C1.staticProp]' of type '() => void' is not assignable to 'number' index type 'string'. ~~ !!! error TS2449: Class 'C1' used before its declaration. !!! related TS2728 computedPropertyNamesWithStaticProperty.ts:1:7: 'C1' is declared here. @@ -42,6 +46,8 @@ computedPropertyNamesWithStaticProperty.ts(20,6): error TS2449: Class 'C2' used var y = x; } [C2.staticProp]() { } + ~~~~~~~~~~~~~~~ +!!! error TS2411: Property '[C2.staticProp]' of type '() => void' is not assignable to 'number' index type 'string'. ~~ !!! error TS2449: Class 'C2' used before its declaration. !!! related TS2728 computedPropertyNamesWithStaticProperty.ts:12:8: 'C2' is declared here. diff --git a/tests/baselines/reference/isolatedDeclarationErrorsClasses.errors.txt b/tests/baselines/reference/isolatedDeclarationErrorsClasses.errors.txt index 90ceb463b9ce6..8a577dfa9eac3 100644 --- a/tests/baselines/reference/isolatedDeclarationErrorsClasses.errors.txt +++ b/tests/baselines/reference/isolatedDeclarationErrorsClasses.errors.txt @@ -7,25 +7,31 @@ isolatedDeclarationErrorsClasses.ts(11,9): error TS9009: At least one accessor m isolatedDeclarationErrorsClasses.ts(12,9): error TS7032: Property 'setOnly' implicitly has type 'any', because its set accessor lacks a parameter type annotation. isolatedDeclarationErrorsClasses.ts(12,17): error TS7006: Parameter 'value' implicitly has an 'any' type. isolatedDeclarationErrorsClasses.ts(36,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. +isolatedDeclarationErrorsClasses.ts(36,5): error TS2411: Property '[missing]' of type 'number' is not assignable to 'string' index type '() => void'. isolatedDeclarationErrorsClasses.ts(36,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(36,6): error TS2304: Cannot find name 'missing'. isolatedDeclarationErrorsClasses.ts(38,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. +isolatedDeclarationErrorsClasses.ts(40,5): error TS2411: Property '[noParamAnnotationLiteralName]' of type '(v: string) => void' is not assignable to 'string' index type '() => void'. isolatedDeclarationErrorsClasses.ts(40,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(42,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. +isolatedDeclarationErrorsClasses.ts(44,5): error TS2411: Property '[noParamAnnotationStringName]' of type '(v: any) => void' is not assignable to 'string' index type '() => void'. isolatedDeclarationErrorsClasses.ts(44,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(44,35): error TS7006: Parameter 'v' implicitly has an 'any' type. +isolatedDeclarationErrorsClasses.ts(46,9): error TS2411: Property '[noAnnotationStringName]' of type 'number' is not assignable to 'string' index type '() => void'. isolatedDeclarationErrorsClasses.ts(46,9): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(48,9): error TS7032: Property '[noParamAnnotationStringName]' implicitly has type 'any', because its set accessor lacks a parameter type annotation. isolatedDeclarationErrorsClasses.ts(48,9): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(48,39): error TS7006: Parameter 'value' implicitly has an 'any' type. isolatedDeclarationErrorsClasses.ts(50,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. +isolatedDeclarationErrorsClasses.ts(50,5): error TS2411: Property '[("A" + "B") as "AB"]' of type 'number' is not assignable to 'string' index type '() => void'. isolatedDeclarationErrorsClasses.ts(50,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(55,5): error TS1169: A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type. +isolatedDeclarationErrorsClasses.ts(56,5): error TS2411: Property '[noAnnotationLiteralName]' of type '() => any' is not assignable to 'string' index type '10'. isolatedDeclarationErrorsClasses.ts(56,5): error TS7010: '[noAnnotationLiteralName]', which lacks return-type annotation, implicitly has an 'any' return type. isolatedDeclarationErrorsClasses.ts(56,5): error TS9013: Expression type can't be inferred with --isolatedDeclarations. -==== isolatedDeclarationErrorsClasses.ts (25 errors) ==== +==== isolatedDeclarationErrorsClasses.ts (31 errors) ==== export class Cls { field = 1 + 1; @@ -86,6 +92,8 @@ isolatedDeclarationErrorsClasses.ts(56,5): error TS9013: Expression type can't b ~~~~~~~~~ !!! 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 '[missing]' of type 'number' is not assignable to 'string' index type '() => void'. + ~~~~~~~~~ !!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. ~~~~~~~ !!! error TS2304: Cannot find name 'missing'. @@ -96,6 +104,8 @@ isolatedDeclarationErrorsClasses.ts(56,5): error TS9013: Expression type can't b [noParamAnnotationLiteralName](v: string): void { } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2411: Property '[noParamAnnotationLiteralName]' of type '(v: string) => void' is not assignable to 'string' index type '() => void'. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. [noAnnotationStringName]() { } @@ -104,12 +114,16 @@ isolatedDeclarationErrorsClasses.ts(56,5): error TS9013: Expression type can't b [noParamAnnotationStringName](v): void { } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2411: Property '[noParamAnnotationStringName]' of type '(v: any) => void' is not assignable to 'string' index type '() => void'. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. ~ !!! error TS7006: Parameter 'v' implicitly has an 'any' type. get [noAnnotationStringName]() { return 0;} ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2411: Property '[noAnnotationStringName]' of type 'number' is not assignable to 'string' index type '() => void'. + ~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. set [noParamAnnotationStringName](value) { } @@ -124,6 +138,8 @@ isolatedDeclarationErrorsClasses.ts(56,5): error TS9013: Expression type can't b ~~~~~~~~~~~~~~~~~~~~~ !!! 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 '[("A" + "B") as "AB"]' of type 'number' is not assignable to 'string' index type '() => void'. + ~~~~~~~~~~~~~~~~~~~~~ !!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. } @@ -134,6 +150,8 @@ isolatedDeclarationErrorsClasses.ts(56,5): error TS9013: Expression type can't b !!! error TS1169: A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type. [noAnnotationLiteralName](); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2411: Property '[noAnnotationLiteralName]' of type '() => any' is not assignable to 'string' index type '10'. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS7010: '[noAnnotationLiteralName]', which lacks return-type annotation, implicitly has an 'any' return type. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS9013: Expression type can't be inferred with --isolatedDeclarations. 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 From b49bf3c422e4c8982420cd668f203c2592359982 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 4 Sep 2024 15:52:37 -0700 Subject: [PATCH 3/8] Declaration emit support for late bound index signatures --- src/compiler/checker.ts | 22 +++++++++++++++++++ src/compiler/transformers/declarations.ts | 4 +++- src/compiler/types.ts | 1 + ...ssNonUniqueSymbolMethodHasSymbolIndexer.js | 1 + 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c6d9bd69acd70..269f6cbcee676 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1122,6 +1122,7 @@ import { WithStatement, YieldExpression, isIndexSignatureDeclaration, + MutableNodeArray, } from "./_namespaces/ts.js"; import * as moduleSpecifiers from "./_namespaces/ts.moduleSpecifiers.js"; import * as performance from "./_namespaces/ts.performance.js"; @@ -50495,6 +50496,27 @@ 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); + let result; + for (const infoList of [staticInfos, instanceInfos]) { + if (!length(infoList)) continue; + result ||= []; + for (const info of infoList!) { + 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/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index b12c3acf84c3e..da0c2dc15b705 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, @@ -1654,7 +1655,8 @@ export function transformDeclarations(context: TransformationContext) { /*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 7a7652eece24d..a9852b8ed5be3 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5866,6 +5866,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/classNonUniqueSymbolMethodHasSymbolIndexer.js b/tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.js index e52b25c702203..b62a61483a00d 100644 --- a/tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.js +++ b/tests/baselines/reference/classNonUniqueSymbolMethodHasSymbolIndexer.js @@ -28,6 +28,7 @@ export const Mixer = Mix(class { //// [classNonUniqueSymbolMethodHasSymbolIndexer.d.ts] export declare class A { + [x: symbol]: () => number; } export declare const Mixer: { new (): { From 57150e56f1371018fe63fa6e20c36c88450df3d6 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 4 Sep 2024 16:00:15 -0700 Subject: [PATCH 4/8] Support declaration emit --- src/compiler/checker.ts | 1 + src/compiler/emitter.ts | 1 + .../reference/isolatedDeclarationErrorsClasses.errors.txt | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 269f6cbcee676..36f4ad8f5bb7d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -50506,6 +50506,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { 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)); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 98f42996cc86c..13021670dc7be 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1163,6 +1163,7 @@ export const notImplementedResolver: EmitResolver = { getDeclarationStatementsForSourceFile: notImplemented, isImportRequiredByAugmentation: notImplemented, isDefinitelyReferenceToGlobalSymbolObject: notImplemented, + createLateBoundIndexSignatures: notImplemented, }; const enum PipelinePhase { diff --git a/tests/baselines/reference/isolatedDeclarationErrorsClasses.errors.txt b/tests/baselines/reference/isolatedDeclarationErrorsClasses.errors.txt index 8a577dfa9eac3..f23a18cfca814 100644 --- a/tests/baselines/reference/isolatedDeclarationErrorsClasses.errors.txt +++ b/tests/baselines/reference/isolatedDeclarationErrorsClasses.errors.txt @@ -1,3 +1,4 @@ +error TS-1: Pre-emit (32) and post-emit (31) diagnostic counts do not match! This can indicate that a semantic _error_ was added by the emit resolver - such an error may not be reflected on the command line or in the editor, but may be captured in a baseline here! isolatedDeclarationErrorsClasses.ts(3,5): error TS9012: Property must have an explicit type annotation with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(4,5): error TS9008: Method must have an explicit return type annotation with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(8,18): error TS7006: Parameter 'p' implicitly has an 'any' type. @@ -31,6 +32,9 @@ isolatedDeclarationErrorsClasses.ts(56,5): error TS7010: '[noAnnotationLiteralNa isolatedDeclarationErrorsClasses.ts(56,5): error TS9013: Expression type can't be inferred with --isolatedDeclarations. +!!! error TS-1: Pre-emit (32) and post-emit (31) diagnostic counts do not match! This can indicate that a semantic _error_ was added by the emit resolver - such an error may not be reflected on the command line or in the editor, but may be captured in a baseline here! +!!! related TS-1: The excess diagnostics are: +!!! related TS9008 isolatedDeclarationErrorsClasses.ts:42:5: Method must have an explicit return type annotation with --isolatedDeclarations. ==== isolatedDeclarationErrorsClasses.ts (31 errors) ==== export class Cls { From 9cbe32a36dfbe53c128a544c4ed01769652266ae Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 4 Sep 2024 16:36:27 -0700 Subject: [PATCH 5/8] Format --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 36f4ad8f5bb7d..b93e1f49d2c64 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, @@ -1121,8 +1123,6 @@ import { WideningContext, WithStatement, YieldExpression, - isIndexSignatureDeclaration, - MutableNodeArray, } from "./_namespaces/ts.js"; import * as moduleSpecifiers from "./_namespaces/ts.moduleSpecifiers.js"; import * as performance from "./_namespaces/ts.performance.js"; From eb0437a6bae40e67006a14944ca9dc0673cc7bdb Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 9 Sep 2024 13:30:44 -0700 Subject: [PATCH 6/8] Use identical logic for type/class implied index signatures and object literal expressions --- src/compiler/checker.ts | 61 +++++++++++++------ .../reference/ES5SymbolProperty2.types | 8 +-- .../reference/ES5SymbolProperty3.types | 3 +- .../reference/ES5SymbolProperty6.types | 4 +- .../reference/ES5SymbolProperty7.types | 3 +- ...pturedParametersInInitializers2.errors.txt | 5 +- .../reference/complicatedPrivacy.types | 4 +- .../computedPropertyNames2_ES5.errors.txt | 5 +- .../computedPropertyNames2_ES6.errors.txt | 5 +- ...PropertyNamesWithStaticProperty.errors.txt | 8 +-- ...clarationEmitAnyComputedPropertyInClass.js | 1 + ...arationEmitComputedPropertyNameEnum2.types | 4 +- ...solatedDeclarationErrorsClasses.errors.txt | 21 +------ .../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/superSymbolIndexedAccess5.types | 10 +-- .../reference/superSymbolIndexedAccess6.types | 10 +-- .../declarationComputedPropertyNames.d.ts | 1 + 24 files changed, 93 insertions(+), 96 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b93e1f49d2c64..b816be5a1c9d5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16255,9 +16255,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return indexSymbol ? getIndexInfosOfIndexSymbol(indexSymbol) : emptyArray; } + // note intentional similarities to index signature building in `checkObjectLiteral` for parity function getIndexInfosOfIndexSymbol(indexSymbol: Symbol): IndexInfo[] { if (indexSymbol.declarations) { const indexInfos: IndexInfo[] = []; + 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) { @@ -16272,25 +16280,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else if (hasLateBindableIndexSignature(declaration)) { - // TODO: Combine index signatures inferred for each member? Or make an index info for each? - // Combined? - // Pros: Easily made, definite compatability with all relevant signatures. - // Cons: Unspecific. Can't make the signature until all declarations are processed - // Individual? - // Pros: Can inject one at a time. Accurate read types via index info applicability filtering. - // Cons: Can't tell at-a-glance which signatures apply? Potentially lots of signatures to track? - // Individual probably better, so is what we do here. - const declName = isBinaryExpression(declaration) ? declaration.left as ElementAccessExpression : (declaration as LateBoundDeclaration).name; const keyType = isElementAccessExpression(declName) ? checkExpressionCached(declName.argumentExpression) : checkComputedPropertyName(declName); - forEachType(keyType, keyType => { - // First-in-wins on multiple declarations right now - combine? leave as multiple, but with compatability error? - if (isValidIndexKeyType(keyType) && !findIndexInfo(indexInfos, keyType)) { - indexInfos.push(createIndexInfo(keyType, getTypeOfVariableOrParameterOrProperty(declaration.symbol), hasEffectiveModifier(declaration, ModifierFlags.Readonly))); + 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); + } } } + // 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, computedPropertySymbols, stringType)); + if (hasComputedNumberProperty && !findIndexInfo(indexInfos, numberType)) indexInfos.push(getObjectLiteralIndexInfo(readonlyComputedNumberProperty, 0, computedPropertySymbols, numberType)); + if (hasComputedSymbolProperty && !findIndexInfo(indexInfos, esSymbolType)) indexInfos.push(getObjectLiteralIndexInfo(readonlyComputedSymbolProperty, 0, computedPropertySymbols, esSymbolType)); return indexInfos; } return emptyArray; @@ -32858,7 +32879,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]; @@ -32871,7 +32893,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 { @@ -33076,9 +33098,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) { 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/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/capturedParametersInInitializers2.errors.txt b/tests/baselines/reference/capturedParametersInInitializers2.errors.txt index c190ffe48f335..7f7e502bfbba2 100644 --- a/tests/baselines/reference/capturedParametersInInitializers2.errors.txt +++ b/tests/baselines/reference/capturedParametersInInitializers2.errors.txt @@ -1,12 +1,11 @@ capturedParametersInInitializers2.ts(3,20): error TS2373: Parameter 'y' cannot reference identifier 'x' declared after it. capturedParametersInInitializers2.ts(4,14): error TS2373: Parameter 'y' cannot reference identifier 'x' declared after it. -capturedParametersInInitializers2.ts(6,9): error TS2411: Property '[z]' of type '() => number' is not assignable to 'number' index type 'number'. capturedParametersInInitializers2.ts(6,10): error TS2373: Parameter 'y' cannot reference identifier 'z' declared after it. capturedParametersInInitializers2.ts(13,26): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. capturedParametersInInitializers2.ts(13,27): error TS2373: Parameter 'y' cannot reference identifier 'x' declared after it. -==== capturedParametersInInitializers2.ts (6 errors) ==== +==== capturedParametersInInitializers2.ts (5 errors) ==== function foo( y = class { static c = x; @@ -17,8 +16,6 @@ capturedParametersInInitializers2.ts(13,27): error TS2373: Parameter 'y' cannot !!! error TS2373: Parameter 'y' cannot reference identifier 'x' declared after it. constructor() { x; } [z]() { return z; } - ~~~ -!!! error TS2411: Property '[z]' of type '() => number' is not assignable to 'number' index type 'number'. ~ !!! error TS2373: Parameter 'y' cannot reference identifier 'z' declared after it. }, 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/computedPropertyNames2_ES5.errors.txt b/tests/baselines/reference/computedPropertyNames2_ES5.errors.txt index 7f438a78ae85f..2d1b4f1abc814 100644 --- a/tests/baselines/reference/computedPropertyNames2_ES5.errors.txt +++ b/tests/baselines/reference/computedPropertyNames2_ES5.errors.txt @@ -1,9 +1,8 @@ computedPropertyNames2_ES5.ts(6,9): error TS2378: A 'get' accessor must return a value. -computedPropertyNames2_ES5.ts(6,9): error TS2411: Property '[accessorName]' of type 'void' is not assignable to 'string' index type '() => void'. computedPropertyNames2_ES5.ts(8,16): error TS2378: A 'get' accessor must return a value. -==== computedPropertyNames2_ES5.ts (3 errors) ==== +==== computedPropertyNames2_ES5.ts (2 errors) ==== var methodName = "method"; var accessorName = "accessor"; class C { @@ -12,8 +11,6 @@ computedPropertyNames2_ES5.ts(8,16): error TS2378: A 'get' accessor must return get [accessorName]() { } ~~~~~~~~~~~~~~ !!! error TS2378: A 'get' accessor must return a value. - ~~~~~~~~~~~~~~ -!!! error TS2411: Property '[accessorName]' of type 'void' is not assignable to 'string' index type '() => void'. set [accessorName](v) { } static get [accessorName]() { } ~~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/computedPropertyNames2_ES6.errors.txt b/tests/baselines/reference/computedPropertyNames2_ES6.errors.txt index bdf812aaf93d7..e9f4abaf8f56a 100644 --- a/tests/baselines/reference/computedPropertyNames2_ES6.errors.txt +++ b/tests/baselines/reference/computedPropertyNames2_ES6.errors.txt @@ -1,9 +1,8 @@ computedPropertyNames2_ES6.ts(6,9): error TS2378: A 'get' accessor must return a value. -computedPropertyNames2_ES6.ts(6,9): error TS2411: Property '[accessorName]' of type 'void' is not assignable to 'string' index type '() => void'. computedPropertyNames2_ES6.ts(8,16): error TS2378: A 'get' accessor must return a value. -==== computedPropertyNames2_ES6.ts (3 errors) ==== +==== computedPropertyNames2_ES6.ts (2 errors) ==== var methodName = "method"; var accessorName = "accessor"; class C { @@ -12,8 +11,6 @@ computedPropertyNames2_ES6.ts(8,16): error TS2378: A 'get' accessor must return get [accessorName]() { } ~~~~~~~~~~~~~~ !!! error TS2378: A 'get' accessor must return a value. - ~~~~~~~~~~~~~~ -!!! error TS2411: Property '[accessorName]' of type 'void' is not assignable to 'string' index type '() => void'. set [accessorName](v) { } static get [accessorName]() { } ~~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/computedPropertyNamesWithStaticProperty.errors.txt b/tests/baselines/reference/computedPropertyNamesWithStaticProperty.errors.txt index 5e36265fb4766..466c66649665c 100644 --- a/tests/baselines/reference/computedPropertyNamesWithStaticProperty.errors.txt +++ b/tests/baselines/reference/computedPropertyNamesWithStaticProperty.errors.txt @@ -1,14 +1,12 @@ computedPropertyNamesWithStaticProperty.ts(3,10): error TS2449: Class 'C1' used before its declaration. computedPropertyNamesWithStaticProperty.ts(6,10): error TS2449: Class 'C1' used before its declaration. -computedPropertyNamesWithStaticProperty.ts(9,5): error TS2411: Property '[C1.staticProp]' of type '() => void' is not assignable to 'number' index type 'string'. computedPropertyNamesWithStaticProperty.ts(9,6): error TS2449: Class 'C1' used before its declaration. computedPropertyNamesWithStaticProperty.ts(14,10): error TS2449: Class 'C2' used before its declaration. computedPropertyNamesWithStaticProperty.ts(17,10): error TS2449: Class 'C2' used before its declaration. -computedPropertyNamesWithStaticProperty.ts(20,5): error TS2411: Property '[C2.staticProp]' of type '() => void' is not assignable to 'number' index type 'string'. computedPropertyNamesWithStaticProperty.ts(20,6): error TS2449: Class 'C2' used before its declaration. -==== computedPropertyNamesWithStaticProperty.ts (8 errors) ==== +==== computedPropertyNamesWithStaticProperty.ts (6 errors) ==== class C1 { static staticProp = 10; get [C1.staticProp]() { @@ -24,8 +22,6 @@ computedPropertyNamesWithStaticProperty.ts(20,6): error TS2449: Class 'C2' used var y = x; } [C1.staticProp]() { } - ~~~~~~~~~~~~~~~ -!!! error TS2411: Property '[C1.staticProp]' of type '() => void' is not assignable to 'number' index type 'string'. ~~ !!! error TS2449: Class 'C1' used before its declaration. !!! related TS2728 computedPropertyNamesWithStaticProperty.ts:1:7: 'C1' is declared here. @@ -46,8 +42,6 @@ computedPropertyNamesWithStaticProperty.ts(20,6): error TS2449: Class 'C2' used var y = x; } [C2.staticProp]() { } - ~~~~~~~~~~~~~~~ -!!! error TS2411: Property '[C2.staticProp]' of type '() => void' is not assignable to 'number' index type 'string'. ~~ !!! error TS2449: Class 'C2' used before its declaration. !!! related TS2728 computedPropertyNamesWithStaticProperty.ts:12:8: 'C2' is declared here. 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/isolatedDeclarationErrorsClasses.errors.txt b/tests/baselines/reference/isolatedDeclarationErrorsClasses.errors.txt index f23a18cfca814..fd58e7f478d90 100644 --- a/tests/baselines/reference/isolatedDeclarationErrorsClasses.errors.txt +++ b/tests/baselines/reference/isolatedDeclarationErrorsClasses.errors.txt @@ -1,4 +1,3 @@ -error TS-1: Pre-emit (32) and post-emit (31) diagnostic counts do not match! This can indicate that a semantic _error_ was added by the emit resolver - such an error may not be reflected on the command line or in the editor, but may be captured in a baseline here! isolatedDeclarationErrorsClasses.ts(3,5): error TS9012: Property must have an explicit type annotation with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(4,5): error TS9008: Method must have an explicit return type annotation with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(8,18): error TS7006: Parameter 'p' implicitly has an 'any' type. @@ -8,23 +7,18 @@ isolatedDeclarationErrorsClasses.ts(11,9): error TS9009: At least one accessor m isolatedDeclarationErrorsClasses.ts(12,9): error TS7032: Property 'setOnly' implicitly has type 'any', because its set accessor lacks a parameter type annotation. isolatedDeclarationErrorsClasses.ts(12,17): error TS7006: Parameter 'value' implicitly has an 'any' type. isolatedDeclarationErrorsClasses.ts(36,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. -isolatedDeclarationErrorsClasses.ts(36,5): error TS2411: Property '[missing]' of type 'number' is not assignable to 'string' index type '() => void'. isolatedDeclarationErrorsClasses.ts(36,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(36,6): error TS2304: Cannot find name 'missing'. isolatedDeclarationErrorsClasses.ts(38,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. -isolatedDeclarationErrorsClasses.ts(40,5): error TS2411: Property '[noParamAnnotationLiteralName]' of type '(v: string) => void' is not assignable to 'string' index type '() => void'. isolatedDeclarationErrorsClasses.ts(40,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(42,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. -isolatedDeclarationErrorsClasses.ts(44,5): error TS2411: Property '[noParamAnnotationStringName]' of type '(v: any) => void' is not assignable to 'string' index type '() => void'. isolatedDeclarationErrorsClasses.ts(44,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(44,35): error TS7006: Parameter 'v' implicitly has an 'any' type. -isolatedDeclarationErrorsClasses.ts(46,9): error TS2411: Property '[noAnnotationStringName]' of type 'number' is not assignable to 'string' index type '() => void'. isolatedDeclarationErrorsClasses.ts(46,9): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(48,9): error TS7032: Property '[noParamAnnotationStringName]' implicitly has type 'any', because its set accessor lacks a parameter type annotation. isolatedDeclarationErrorsClasses.ts(48,9): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(48,39): error TS7006: Parameter 'value' implicitly has an 'any' type. isolatedDeclarationErrorsClasses.ts(50,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. -isolatedDeclarationErrorsClasses.ts(50,5): error TS2411: Property '[("A" + "B") as "AB"]' of type 'number' is not assignable to 'string' index type '() => void'. isolatedDeclarationErrorsClasses.ts(50,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(55,5): error TS1169: A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type. isolatedDeclarationErrorsClasses.ts(56,5): error TS2411: Property '[noAnnotationLiteralName]' of type '() => any' is not assignable to 'string' index type '10'. @@ -32,10 +26,7 @@ isolatedDeclarationErrorsClasses.ts(56,5): error TS7010: '[noAnnotationLiteralNa isolatedDeclarationErrorsClasses.ts(56,5): error TS9013: Expression type can't be inferred with --isolatedDeclarations. -!!! error TS-1: Pre-emit (32) and post-emit (31) diagnostic counts do not match! This can indicate that a semantic _error_ was added by the emit resolver - such an error may not be reflected on the command line or in the editor, but may be captured in a baseline here! -!!! related TS-1: The excess diagnostics are: -!!! related TS9008 isolatedDeclarationErrorsClasses.ts:42:5: Method must have an explicit return type annotation with --isolatedDeclarations. -==== isolatedDeclarationErrorsClasses.ts (31 errors) ==== +==== isolatedDeclarationErrorsClasses.ts (26 errors) ==== export class Cls { field = 1 + 1; @@ -96,8 +87,6 @@ isolatedDeclarationErrorsClasses.ts(56,5): error TS9013: Expression type can't b ~~~~~~~~~ !!! 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 '[missing]' of type 'number' is not assignable to 'string' index type '() => void'. - ~~~~~~~~~ !!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. ~~~~~~~ !!! error TS2304: Cannot find name 'missing'. @@ -108,8 +97,6 @@ isolatedDeclarationErrorsClasses.ts(56,5): error TS9013: Expression type can't b [noParamAnnotationLiteralName](v: string): void { } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property '[noParamAnnotationLiteralName]' of type '(v: string) => void' is not assignable to 'string' index type '() => void'. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. [noAnnotationStringName]() { } @@ -118,16 +105,12 @@ isolatedDeclarationErrorsClasses.ts(56,5): error TS9013: Expression type can't b [noParamAnnotationStringName](v): void { } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property '[noParamAnnotationStringName]' of type '(v: any) => void' is not assignable to 'string' index type '() => void'. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. ~ !!! error TS7006: Parameter 'v' implicitly has an 'any' type. get [noAnnotationStringName]() { return 0;} ~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property '[noAnnotationStringName]' of type 'number' is not assignable to 'string' index type '() => void'. - ~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. set [noParamAnnotationStringName](value) { } @@ -142,8 +125,6 @@ isolatedDeclarationErrorsClasses.ts(56,5): error TS9013: Expression type can't b ~~~~~~~~~~~~~~~~~~~~~ !!! 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 '[("A" + "B") as "AB"]' of type 'number' is not assignable to 'string' index type '() => void'. - ~~~~~~~~~~~~~~~~~~~~~ !!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. } 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/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; From df020decba65a61787d20670b2e89d6d3011d542 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 9 Sep 2024 13:47:34 -0700 Subject: [PATCH 7/8] Note to self: swap fourslash quickinfo verify tests to baseline tests --- tests/cases/fourslash/quickInfoInInvalidIndexSignature.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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}"); From 708095aeae89361a956b147a8765f11355daae36 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 10 Sep 2024 13:06:40 -0700 Subject: [PATCH 8/8] Actually include the types of explicit properties in implies index signature types - cant forget those --- src/compiler/checker.ts | 15 ++++++++------- src/compiler/types.ts | 2 +- tests/baselines/reference/api/typescript.d.ts | 2 +- .../isolatedDeclarationErrorsClasses.errors.txt | 5 +---- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b816be5a1c9d5..b228860ab99e6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14207,7 +14207,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) { @@ -16252,11 +16252,11 @@ 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; } // note intentional similarities to index signature building in `checkObjectLiteral` for parity - function getIndexInfosOfIndexSymbol(indexSymbol: Symbol): IndexInfo[] { + function getIndexInfosOfIndexSymbol(indexSymbol: Symbol, siblingSymbols: Symbol[] | undefined = indexSymbol.parent ? arrayFrom(getMembersOfSymbol(indexSymbol.parent).values()) : undefined): IndexInfo[] { if (indexSymbol.declarations) { const indexInfos: IndexInfo[] = []; let hasComputedNumberProperty = false; @@ -16308,10 +16308,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } + 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, computedPropertySymbols, stringType)); - if (hasComputedNumberProperty && !findIndexInfo(indexInfos, numberType)) indexInfos.push(getObjectLiteralIndexInfo(readonlyComputedNumberProperty, 0, computedPropertySymbols, numberType)); - if (hasComputedSymbolProperty && !findIndexInfo(indexInfos, esSymbolType)) indexInfos.push(getObjectLiteralIndexInfo(readonlyComputedSymbolProperty, 0, computedPropertySymbols, esSymbolType)); + 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; @@ -50523,7 +50524,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const sym = cls.symbol; const staticInfos = getIndexInfosOfType(getTypeOfSymbol(sym)); const instanceIndexSymbol = getIndexSymbol(sym); - const instanceInfos = instanceIndexSymbol && getIndexInfosOfIndexSymbol(instanceIndexSymbol); + const instanceInfos = instanceIndexSymbol && getIndexInfosOfIndexSymbol(instanceIndexSymbol, arrayFrom(getMembersOfSymbol(sym).values())); let result; for (const infoList of [staticInfos, instanceInfos]) { if (!length(infoList)) continue; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a9852b8ed5be3..d332cf917df1e 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; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 5122694b16787..d75ab777df999 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -6119,7 +6119,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/isolatedDeclarationErrorsClasses.errors.txt b/tests/baselines/reference/isolatedDeclarationErrorsClasses.errors.txt index fd58e7f478d90..90ceb463b9ce6 100644 --- a/tests/baselines/reference/isolatedDeclarationErrorsClasses.errors.txt +++ b/tests/baselines/reference/isolatedDeclarationErrorsClasses.errors.txt @@ -21,12 +21,11 @@ isolatedDeclarationErrorsClasses.ts(48,39): error TS7006: Parameter 'value' impl isolatedDeclarationErrorsClasses.ts(50,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type. isolatedDeclarationErrorsClasses.ts(50,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations. isolatedDeclarationErrorsClasses.ts(55,5): error TS1169: A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type. -isolatedDeclarationErrorsClasses.ts(56,5): error TS2411: Property '[noAnnotationLiteralName]' of type '() => any' is not assignable to 'string' index type '10'. isolatedDeclarationErrorsClasses.ts(56,5): error TS7010: '[noAnnotationLiteralName]', which lacks return-type annotation, implicitly has an 'any' return type. isolatedDeclarationErrorsClasses.ts(56,5): error TS9013: Expression type can't be inferred with --isolatedDeclarations. -==== isolatedDeclarationErrorsClasses.ts (26 errors) ==== +==== isolatedDeclarationErrorsClasses.ts (25 errors) ==== export class Cls { field = 1 + 1; @@ -135,8 +134,6 @@ isolatedDeclarationErrorsClasses.ts(56,5): error TS9013: Expression type can't b !!! error TS1169: A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type. [noAnnotationLiteralName](); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2411: Property '[noAnnotationLiteralName]' of type '() => any' is not assignable to 'string' index type '10'. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS7010: '[noAnnotationLiteralName]', which lacks return-type annotation, implicitly has an 'any' return type. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS9013: Expression type can't be inferred with --isolatedDeclarations.