Skip to content

Commit 8d550c8

Browse files
committed
Skip non-public members when resolving reverse-mapped types
1 parent 09b1db0 commit 8d550c8

4 files changed

Lines changed: 131 additions & 0 deletions

File tree

‎tsc/internal/checker/inference.go‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,11 @@ func (c *Checker) resolveReverseMappedTypeMembers(t *Type) {
11201120
members := make(ast.SymbolTable)
11211121
limitedConstraint := c.getLimitedConstraint(t)
11221122
for _, prop := range c.getPropertiesOfType(r.source) {
1123+
// Private and protected properties are never produced by keyof, so they have no counterpart in a
1124+
// reverse mapped type. Copying them would surface them as public properties of the inferred type.
1125+
if getDeclarationModifierFlagsFromSymbol(prop)&ast.ModifierFlagsNonPublicAccessibilityModifier != 0 {
1126+
continue
1127+
}
11231128
// In case of a reverse mapped type with an intersection constraint, if we were able to
11241129
// extract the filtering type literals we skip those properties that are not assignable to them,
11251130
// because the extra properties wouldn't get through the application of the mapped type anyway
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//// [tests/cases/compiler/reverseMappedTypePrivateMembers.ts] ////
2+
3+
=== reverseMappedTypePrivateMembers.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/64593
5+
6+
class Entity {
7+
>Entity : Symbol(Entity, Decl(reverseMappedTypePrivateMembers.ts, 0, 0))
8+
9+
private secret = 1;
10+
>secret : Symbol(Entity.secret, Decl(reverseMappedTypePrivateMembers.ts, 2, 14))
11+
12+
protected hidden = 2;
13+
>hidden : Symbol(Entity.hidden, Decl(reverseMappedTypePrivateMembers.ts, 3, 23))
14+
15+
markChanged(field: string): void {}
16+
>markChanged : Symbol(Entity.markChanged, Decl(reverseMappedTypePrivateMembers.ts, 4, 25))
17+
>field : Symbol(field, Decl(reverseMappedTypePrivateMembers.ts, 5, 16))
18+
}
19+
class Account extends Entity {
20+
>Account : Symbol(Account, Decl(reverseMappedTypePrivateMembers.ts, 6, 1))
21+
>Entity : Symbol(Entity, Decl(reverseMappedTypePrivateMembers.ts, 0, 0))
22+
23+
emailAddress = '';
24+
>emailAddress : Symbol(Account.emailAddress, Decl(reverseMappedTypePrivateMembers.ts, 7, 30))
25+
}
26+
27+
declare function getAccount<T extends object = object>(): Readonly<Account & T>;
28+
>getAccount : Symbol(getAccount, Decl(reverseMappedTypePrivateMembers.ts, 9, 1))
29+
>T : Symbol(T, Decl(reverseMappedTypePrivateMembers.ts, 11, 28))
30+
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
31+
>Account : Symbol(Account, Decl(reverseMappedTypePrivateMembers.ts, 6, 1))
32+
>T : Symbol(T, Decl(reverseMappedTypePrivateMembers.ts, 11, 28))
33+
34+
declare function getAccountPlain(): Readonly<Account & object>;
35+
>getAccountPlain : Symbol(getAccountPlain, Decl(reverseMappedTypePrivateMembers.ts, 11, 80))
36+
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
37+
>Account : Symbol(Account, Decl(reverseMappedTypePrivateMembers.ts, 6, 1))
38+
39+
export const plain = getAccountPlain() as Account;
40+
>plain : Symbol(plain, Decl(reverseMappedTypePrivateMembers.ts, 14, 12))
41+
>getAccountPlain : Symbol(getAccountPlain, Decl(reverseMappedTypePrivateMembers.ts, 11, 80))
42+
>Account : Symbol(Account, Decl(reverseMappedTypePrivateMembers.ts, 6, 1))
43+
44+
export const explicit = getAccount<object>() as Account;
45+
>explicit : Symbol(explicit, Decl(reverseMappedTypePrivateMembers.ts, 15, 12))
46+
>getAccount : Symbol(getAccount, Decl(reverseMappedTypePrivateMembers.ts, 9, 1))
47+
>Account : Symbol(Account, Decl(reverseMappedTypePrivateMembers.ts, 6, 1))
48+
49+
export const inferred = getAccount() as Account;
50+
>inferred : Symbol(inferred, Decl(reverseMappedTypePrivateMembers.ts, 16, 12))
51+
>getAccount : Symbol(getAccount, Decl(reverseMappedTypePrivateMembers.ts, 9, 1))
52+
>Account : Symbol(Account, Decl(reverseMappedTypePrivateMembers.ts, 6, 1))
53+
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//// [tests/cases/compiler/reverseMappedTypePrivateMembers.ts] ////
2+
3+
=== reverseMappedTypePrivateMembers.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/64593
5+
6+
class Entity {
7+
>Entity : Entity
8+
9+
private secret = 1;
10+
>secret : number
11+
>1 : 1
12+
13+
protected hidden = 2;
14+
>hidden : number
15+
>2 : 2
16+
17+
markChanged(field: string): void {}
18+
>markChanged : (field: string) => void
19+
>field : string
20+
}
21+
class Account extends Entity {
22+
>Account : Account
23+
>Entity : Entity
24+
25+
emailAddress = '';
26+
>emailAddress : string
27+
>'' : ""
28+
}
29+
30+
declare function getAccount<T extends object = object>(): Readonly<Account & T>;
31+
>getAccount : <T extends object = object>() => Readonly<Account & T>
32+
33+
declare function getAccountPlain(): Readonly<Account & object>;
34+
>getAccountPlain : () => Readonly<Account & object>
35+
36+
export const plain = getAccountPlain() as Account;
37+
>plain : Account
38+
>getAccountPlain() as Account : Account
39+
>getAccountPlain() : Readonly<Account & object>
40+
>getAccountPlain : () => Readonly<Account & object>
41+
42+
export const explicit = getAccount<object>() as Account;
43+
>explicit : Account
44+
>getAccount<object>() as Account : Account
45+
>getAccount<object>() : Readonly<Account & object>
46+
>getAccount : <T extends object = object>() => Readonly<Account & T>
47+
48+
export const inferred = getAccount() as Account;
49+
>inferred : Account
50+
>getAccount() as Account : Account
51+
>getAccount() : Readonly<Account & { markChanged: (field: string) => void; emailAddress: string; }>
52+
>getAccount : <T extends object = object>() => Readonly<Account & T>
53+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
// https://github.com/microsoft/TypeScript/issues/64593
5+
6+
class Entity {
7+
private secret = 1;
8+
protected hidden = 2;
9+
markChanged(field: string): void {}
10+
}
11+
class Account extends Entity {
12+
emailAddress = '';
13+
}
14+
15+
declare function getAccount<T extends object = object>(): Readonly<Account & T>;
16+
declare function getAccountPlain(): Readonly<Account & object>;
17+
18+
export const plain = getAccountPlain() as Account;
19+
export const explicit = getAccount<object>() as Account;
20+
export const inferred = getAccount() as Account;

0 commit comments

Comments
 (0)