Skip to content

Support interpreting non-literal computed properties in classes as implicit index signatures #59860

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Actually include the types of explicit properties in implies index si…
…gnature types - cant forget those
  • Loading branch information
weswigham committed Sep 10, 2024
commit 708095aeae89361a956b147a8765f11355daae36
15 changes: 8 additions & 7 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Comment on lines +16313 to +16315
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are all of the findIndexInfo calls likely to cost a bunch or is indexInfos just always short?

Copy link
Member Author

@weswigham weswigham Sep 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, it's always short (there's usually just string or number indexes, if any) - in theory, a user could explicitly define hundreds of pattern literal index infos and it'd be bad, however, and you'd prefer you did the up-front work to make a map keyed on key type (if you had multiple kinds of computed names). But that's not code anyone's realistically writing.

return indexInfos;
}
return emptyArray;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy