diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cbdb92933023e..81466f7b829bb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -42066,6 +42066,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkIndexedAccessIndexType(type: Type, accessNode: IndexedAccessTypeNode | ElementAccessExpression) { if (!(type.flags & TypeFlags.IndexedAccess)) { + if (isIndexedAccessTypeNode(accessNode)) { + const indexType = getTypeFromTypeNode(accessNode.indexType); + const objectType = getTypeFromTypeNode(accessNode.objectType); + const propertyName = getPropertyNameFromIndex(indexType, accessNode); + if (propertyName && getEmitDeclarations(compilerOptions)) { + const propertySymbol = forEachType(getApparentType(objectType), t => getPropertyOfType(t, propertyName)); + if (propertySymbol && getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.Private) { + error(accessNode, Diagnostics.Private_member_0_cannot_be_accessed_via_indexed_access, unescapeLeadingUnderscores(propertyName)); + return errorType; + } + } + } return type; } // Check if the index type is assignable to 'keyof T' for the object type. @@ -42085,14 +42097,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return type; } - if (isGenericObjectType(objectType)) { - const propertyName = getPropertyNameFromIndex(indexType, accessNode); - if (propertyName) { - const propertySymbol = forEachType(getApparentType(objectType), t => getPropertyOfType(t, propertyName)); - if (propertySymbol && getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.NonPublicAccessibilityModifier) { - error(accessNode, Diagnostics.Private_or_protected_member_0_cannot_be_accessed_on_a_type_parameter, unescapeLeadingUnderscores(propertyName)); - return errorType; - } + const propertyName = getPropertyNameFromIndex(indexType, accessNode); + if (propertyName) { + const propertySymbol = forEachType(getApparentType(objectType), t => getPropertyOfType(t, propertyName)); + if (propertySymbol && getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.NonPublicAccessibilityModifier) { + error(accessNode, Diagnostics.Private_or_protected_member_0_cannot_be_accessed_on_a_type_parameter, unescapeLeadingUnderscores(propertyName)); + return errorType; } } error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(objectType)); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index be2fe3957b20a..a8926e5af4cab 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4436,6 +4436,10 @@ "category": "Error", "code": 4128 }, + "Private member '{0}' cannot be accessed via indexed access.": { + "category": "Error", + "code": 4129 + }, "The current host does not support the '{0}' option.": { "category": "Error", diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 23f8d844c9856..03ab916cd4741 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -748,7 +748,13 @@ export type ConfiguredProjectToAnyReloadKind = Map< >; /** @internal */ -export type DefaultConfiguredProjectResult = ReturnType; +export interface DefaultConfiguredProjectResult { + defaultProject: ConfiguredProject | undefined; + tsconfigProject: ConfiguredProject | undefined; + sentConfigDiag: Set; + seenProjects: ConfigureProjectToLoadKind; + seenConfigs: Set | undefined; +} /** @internal */ export interface FindCreateOrLoadConfiguredProjectResult { @@ -4534,7 +4540,7 @@ export class ProjectService { allowDeferredClosed?: boolean, /** Used with ConfiguredProjectLoadKind.Reload to check if this project was already reloaded */ reloadedProjects?: ConfiguredProjectToAnyReloadKind, - ) { + ): DefaultConfiguredProjectResult { const infoIsOpenScriptInfo = isOpenScriptInfo(info); const optimizedKind = toConfiguredProjectLoadOptimized(kind); const seenProjects: ConfigureProjectToLoadKind = new Map(); diff --git a/tests/baselines/reference/indexedAccessOfConcreteNonpublicFields.errors.txt b/tests/baselines/reference/indexedAccessOfConcreteNonpublicFields.errors.txt new file mode 100644 index 0000000000000..ae22871348ea8 --- /dev/null +++ b/tests/baselines/reference/indexedAccessOfConcreteNonpublicFields.errors.txt @@ -0,0 +1,12 @@ +indexedAccessOfConcreteNonpublicFields.ts(4,22): error TS4129: Private member '_property' cannot be accessed via indexed access. + + +==== indexedAccessOfConcreteNonpublicFields.ts (1 errors) ==== + export class Foo { + private _property: string = ''; + protected _property2: string = ''; + constructor(arg: Foo['_property'], other: Foo['_property2']) { + ~~~~~~~~~~~~~~~~ +!!! error TS4129: Private member '_property' cannot be accessed via indexed access. + } + } \ No newline at end of file diff --git a/tests/baselines/reference/indexedAccessOfConcreteNonpublicFields.js b/tests/baselines/reference/indexedAccessOfConcreteNonpublicFields.js new file mode 100644 index 0000000000000..47ba4d935033c --- /dev/null +++ b/tests/baselines/reference/indexedAccessOfConcreteNonpublicFields.js @@ -0,0 +1,30 @@ +//// [tests/cases/compiler/indexedAccessOfConcreteNonpublicFields.ts] //// + +//// [indexedAccessOfConcreteNonpublicFields.ts] +export class Foo { + private _property: string = ''; + protected _property2: string = ''; + constructor(arg: Foo['_property'], other: Foo['_property2']) { + } +} + +//// [indexedAccessOfConcreteNonpublicFields.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Foo = void 0; +var Foo = /** @class */ (function () { + function Foo(arg, other) { + this._property = ''; + this._property2 = ''; + } + return Foo; +}()); +exports.Foo = Foo; + + +//// [indexedAccessOfConcreteNonpublicFields.d.ts] +export declare class Foo { + private _property; + protected _property2: string; + constructor(arg: Foo['_property'], other: Foo['_property2']); +} diff --git a/tests/baselines/reference/indexedAccessOfConcreteNonpublicFields.symbols b/tests/baselines/reference/indexedAccessOfConcreteNonpublicFields.symbols new file mode 100644 index 0000000000000..e2cf3b4f1377e --- /dev/null +++ b/tests/baselines/reference/indexedAccessOfConcreteNonpublicFields.symbols @@ -0,0 +1,19 @@ +//// [tests/cases/compiler/indexedAccessOfConcreteNonpublicFields.ts] //// + +=== indexedAccessOfConcreteNonpublicFields.ts === +export class Foo { +>Foo : Symbol(Foo, Decl(indexedAccessOfConcreteNonpublicFields.ts, 0, 0)) + + private _property: string = ''; +>_property : Symbol(Foo._property, Decl(indexedAccessOfConcreteNonpublicFields.ts, 0, 18)) + + protected _property2: string = ''; +>_property2 : Symbol(Foo._property2, Decl(indexedAccessOfConcreteNonpublicFields.ts, 1, 35)) + + constructor(arg: Foo['_property'], other: Foo['_property2']) { +>arg : Symbol(arg, Decl(indexedAccessOfConcreteNonpublicFields.ts, 3, 16)) +>Foo : Symbol(Foo, Decl(indexedAccessOfConcreteNonpublicFields.ts, 0, 0)) +>other : Symbol(other, Decl(indexedAccessOfConcreteNonpublicFields.ts, 3, 38)) +>Foo : Symbol(Foo, Decl(indexedAccessOfConcreteNonpublicFields.ts, 0, 0)) + } +} diff --git a/tests/baselines/reference/indexedAccessOfConcreteNonpublicFields.types b/tests/baselines/reference/indexedAccessOfConcreteNonpublicFields.types new file mode 100644 index 0000000000000..a46baaf9aec0b --- /dev/null +++ b/tests/baselines/reference/indexedAccessOfConcreteNonpublicFields.types @@ -0,0 +1,26 @@ +//// [tests/cases/compiler/indexedAccessOfConcreteNonpublicFields.ts] //// + +=== indexedAccessOfConcreteNonpublicFields.ts === +export class Foo { +>Foo : Foo +> : ^^^ + + private _property: string = ''; +>_property : string +> : ^^^^^^ +>'' : "" +> : ^^ + + protected _property2: string = ''; +>_property2 : string +> : ^^^^^^ +>'' : "" +> : ^^ + + constructor(arg: Foo['_property'], other: Foo['_property2']) { +>arg : string +> : ^^^^^^ +>other : string +> : ^^^^^^ + } +} diff --git a/tests/baselines/reference/keyofAndIndexedAccess.errors.txt b/tests/baselines/reference/keyofAndIndexedAccess.errors.txt index e833106df6fe5..7c5ac0e5858e2 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.errors.txt +++ b/tests/baselines/reference/keyofAndIndexedAccess.errors.txt @@ -1,3 +1,4 @@ +keyofAndIndexedAccess.ts(174,14): error TS4129: Private member 'z' cannot be accessed via indexed access. keyofAndIndexedAccess.ts(205,24): error TS2322: Type 'T[keyof T]' is not assignable to type 'object'. Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'object'. Type 'T[string]' is not assignable to type 'object'. @@ -15,7 +16,7 @@ keyofAndIndexedAccess.ts(318,5): error TS2322: Type 'T[K]' is not assignable to Type 'T[string]' is not assignable to type '{}'. -==== keyofAndIndexedAccess.ts (5 errors) ==== +==== keyofAndIndexedAccess.ts (6 errors) ==== class Shape { name: string; width: number; @@ -190,6 +191,8 @@ keyofAndIndexedAccess.ts(318,5): error TS2322: Type 'T[K]' is not assignable to type X = C["x"]; type Y = C["y"]; type Z = C["z"]; + ~~~~~~ +!!! error TS4129: Private member 'z' cannot be accessed via indexed access. let x: X = c["x"]; let y: Y = c["y"]; let z: Z = c["z"]; diff --git a/tests/cases/compiler/indexedAccessOfConcreteNonpublicFields.ts b/tests/cases/compiler/indexedAccessOfConcreteNonpublicFields.ts new file mode 100644 index 0000000000000..f06fb2c04f510 --- /dev/null +++ b/tests/cases/compiler/indexedAccessOfConcreteNonpublicFields.ts @@ -0,0 +1,7 @@ +// @declaration: true +export class Foo { + private _property: string = ''; + protected _property2: string = ''; + constructor(arg: Foo['_property'], other: Foo['_property2']) { + } +} \ No newline at end of file