Skip to content

Consistently error on attempts to access private properties on generic objects #62300

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
36 changes: 27 additions & 9 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42734,12 +42734,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function checkIndexedAccessIndexType(type: Type, accessNode: IndexedAccessTypeNode | ElementAccessExpression) {
if (type.flags & TypeFlags.Never && isIndexedAccessTypeNode(accessNode)) {
if (!checkNonPublicPropertyAccess(getTypeFromTypeNode(accessNode.objectType), getTypeFromTypeNode(accessNode.indexType))) {
return errorType;
}
return type;
}
if (!(type.flags & TypeFlags.IndexedAccess)) {
return type;
}
// Check if the index type is assignable to 'keyof T' for the object type.
const objectType = (type as IndexedAccessType).objectType;
const indexType = (type as IndexedAccessType).indexType;

if (!checkNonPublicPropertyAccess(objectType, indexType)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

class A {
  private declare a: { foo: number };
}

class B {
  declare a: { bar: string };
}

type Test1<T extends A & B> = T["a"];
type Test2<T1 extends A, T2 extends B> = (T1 & T2)["a"];

The added branch related to never is to account for the eager~ reduction of Test2 to never. Because of that, checkIndexedAccessIndexType wouldn't even have a chance to report the error.

In a similar fashion, the existing check had to be moved closer to the top to error at Test1. At the current location, everyType(indexType, t => isTypeAssignableTo(t, objectIndexType) would return before making this check. That's because objectIndexType (keyof T) would be mapped to its reduced apparent type when relating to it as the target. That would become keyof never and that's just PropertyKey - to which the "a" source is assignable to.

return errorType;
}

// skip index type deferral on remapping mapped types
const objectIndexType = isGenericMappedType(objectType) && getMappedTypeNameTypeKind(objectType) === MappedTypeNameTypeKind.Remapping
? getIndexTypeForMappedType(objectType, IndexFlags.None)
Expand All @@ -42754,18 +42765,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
return type;
}
if (isGenericObjectType(objectType)) {
error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(objectType));
return errorType;

function checkNonPublicPropertyAccess(objectType: Type, indexType: Type) {
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;
}
if (propertyName && someType(getApparentType(objectType), t => isNonPublicPropertyOfType(t, propertyName))) {
error(accessNode, Diagnostics.Private_or_protected_member_0_cannot_be_accessed_on_a_type_parameter, unescapeLeadingUnderscores(propertyName));
return false;
}
return true;
}

function isNonPublicPropertyOfType(type: Type, propertyName: __String): boolean {
if (type.flags & TypeFlags.Intersection) {
return some((type as IntersectionType).types, t => isNonPublicPropertyOfType(t, propertyName));
}
const propertySymbol = getPropertyOfType(type, propertyName);
return !!(propertySymbol && getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.NonPublicAccessibilityModifier);
}
error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(objectType));
return errorType;
}

function checkIndexedAccessType(node: IndexedAccessTypeNode) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,41 @@
indexedAccessPrivateMemberOfGenericConstraint.ts(9,24): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(9,32): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(10,27): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(11,27): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(12,37): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(13,37): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(14,23): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(15,37): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(16,37): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(26,25): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(26,33): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(27,28): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(28,28): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(29,38): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(30,38): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(31,24): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(32,38): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(33,38): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(43,33): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(44,28): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(45,28): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(46,38): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(47,38): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(48,24): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(49,38): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(50,38): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(60,25): error TS2536: Type '"a"' cannot be used to index type 'T'.
indexedAccessPrivateMemberOfGenericConstraint.ts(60,33): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(61,28): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(62,28): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(63,38): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(64,38): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(65,24): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(66,38): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
indexedAccessPrivateMemberOfGenericConstraint.ts(67,38): error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.


==== indexedAccessPrivateMemberOfGenericConstraint.ts (3 errors) ====
==== indexedAccessPrivateMemberOfGenericConstraint.ts (35 errors) ====
class A {
private a: number;
}
Expand All @@ -21,4 +53,124 @@ indexedAccessPrivateMemberOfGenericConstraint.ts(10,27): error TS4105: Private o
~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type Z<T extends A & B> = T["a"];
~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type R<T extends A, T2 extends B> = (T | T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type S<T extends B, T2 extends A> = (T | T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type U<T extends A> = (T & B)["a"];
~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type V<T extends A, T2 extends B> = (T & T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type W<T extends B, T2 extends A> = (T & T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.

class C {
declare private a: number;
}

class D {
declare a: string;
}

type X2<T extends C> = [T["a"], (T | D)["a"]];
~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type Y2<T extends C | D> = T["a"];
~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type Z2<T extends C & D> = T["a"];
~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type R2<T extends C, T2 extends D> = (T | T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type S2<T extends D, T2 extends C> = (T | T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type U2<T extends C> = (T & D)["a"];
~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type V2<T extends C, T2 extends D> = (T & T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type W2<T extends D, T2 extends C> = (T & T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.

class E {
declare a: number;
}

class F {
declare private a: string;
}

type X3<T extends E> = [T["a"], (T | F)["a"]];
~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type Y3<T extends E | F> = T["a"];
~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type Z3<T extends E & F> = T["a"];
~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type R3<T extends E, T2 extends F> = (T | T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type S3<T extends F, T2 extends E> = (T | T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type U3<T extends E> = (T & F)["a"];
~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type V3<T extends E, T2 extends F> = (T & T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type W3<T extends F, T2 extends E> = (T & T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.

class G {
declare b: number;
}

class H {
declare private a: string;
}

type X4<T extends G> = [T["a"], (T | H)["a"]];
~~~~~~
!!! error TS2536: Type '"a"' cannot be used to index type 'T'.
~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type Y4<T extends G | H> = T["a"];
~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type Z4<T extends G & H> = T["a"];
~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type R4<T extends G, T2 extends H> = (T | T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type S4<T extends H, T2 extends G> = (T | T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type U4<T extends G> = (T & H)["a"];
~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type V4<T extends G, T2 extends H> = (T & T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.
type W4<T extends H, T2 extends G> = (T & T2)["a"];
~~~~~~~~~~~~~
!!! error TS4105: Private or protected member 'a' cannot be accessed on a type parameter.

Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,62 @@ class B {
type X<T extends A> = [T["a"], (T | B)["a"]];
type Y<T extends A | B> = T["a"];
type Z<T extends A & B> = T["a"];
type R<T extends A, T2 extends B> = (T | T2)["a"];
type S<T extends B, T2 extends A> = (T | T2)["a"];
type U<T extends A> = (T & B)["a"];
type V<T extends A, T2 extends B> = (T & T2)["a"];
type W<T extends B, T2 extends A> = (T & T2)["a"];

class C {
declare private a: number;
}

class D {
declare a: string;
}

type X2<T extends C> = [T["a"], (T | D)["a"]];
type Y2<T extends C | D> = T["a"];
type Z2<T extends C & D> = T["a"];
type R2<T extends C, T2 extends D> = (T | T2)["a"];
type S2<T extends D, T2 extends C> = (T | T2)["a"];
type U2<T extends C> = (T & D)["a"];
type V2<T extends C, T2 extends D> = (T & T2)["a"];
type W2<T extends D, T2 extends C> = (T & T2)["a"];

class E {
declare a: number;
}

class F {
declare private a: string;
}

type X3<T extends E> = [T["a"], (T | F)["a"]];
type Y3<T extends E | F> = T["a"];
type Z3<T extends E & F> = T["a"];
type R3<T extends E, T2 extends F> = (T | T2)["a"];
type S3<T extends F, T2 extends E> = (T | T2)["a"];
type U3<T extends E> = (T & F)["a"];
type V3<T extends E, T2 extends F> = (T & T2)["a"];
type W3<T extends F, T2 extends E> = (T & T2)["a"];

class G {
declare b: number;
}

class H {
declare private a: string;
}

type X4<T extends G> = [T["a"], (T | H)["a"]];
type Y4<T extends G | H> = T["a"];
type Z4<T extends G & H> = T["a"];
type R4<T extends G, T2 extends H> = (T | T2)["a"];
type S4<T extends H, T2 extends G> = (T | T2)["a"];
type U4<T extends G> = (T & H)["a"];
type V4<T extends G, T2 extends H> = (T & T2)["a"];
type W4<T extends H, T2 extends G> = (T & T2)["a"];


//// [indexedAccessPrivateMemberOfGenericConstraint.js]
Expand All @@ -25,3 +81,33 @@ var B = /** @class */ (function () {
}
return B;
}());
var C = /** @class */ (function () {
function C() {
}
return C;
}());
var D = /** @class */ (function () {
function D() {
}
return D;
}());
var E = /** @class */ (function () {
function E() {
}
return E;
}());
var F = /** @class */ (function () {
function F() {
}
return F;
}());
var G = /** @class */ (function () {
function G() {
}
return G;
}());
var H = /** @class */ (function () {
function H() {
}
return H;
}());
Loading
Loading