Skip to content

Commit 2cf5afd

Browse files
authored
Avoid pulling on setter type when only getter type is needed to break circularity (#47818)
1 parent c06849a commit 2cf5afd

5 files changed

+109
-4
lines changed

src/compiler/checker.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -9511,11 +9511,12 @@ namespace ts {
95119511
const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor);
95129512
const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor);
95139513

9514-
const setterType = getAnnotatedAccessorType(setter);
9515-
95169514
// For write operations, prioritize type annotations on the setter
9517-
if (writing && setterType) {
9518-
return instantiateTypeIfNeeded(setterType, symbol);
9515+
if (writing) {
9516+
const setterType = getAnnotatedAccessorType(setter);
9517+
if (setterType) {
9518+
return instantiateTypeIfNeeded(setterType, symbol);
9519+
}
95199520
}
95209521
// Else defer to the getter type
95219522

@@ -9533,6 +9534,7 @@ namespace ts {
95339534
}
95349535

95359536
// If the user didn't specify a return type, try to use the set-accessor's parameter type.
9537+
const setterType = getAnnotatedAccessorType(setter);
95369538
if (setterType) {
95379539
return setterType;
95389540
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//// [mappedTypeCircularReferenceInAccessor.ts]
2+
interface User {
3+
firstName: string,
4+
level: number,
5+
get bestFriend(): User
6+
set bestFriend(user: SerializablePartial<User>)
7+
}
8+
9+
type FilteredKeys<T> = { [K in keyof T]: T[K] extends number ? K : T[K] extends string ? K : T[K] extends boolean ? K : never }[keyof T];
10+
11+
type SerializablePartial<T> = {
12+
[K in FilteredKeys<T>]: T[K]
13+
};
14+
15+
16+
//// [mappedTypeCircularReferenceInAccessor.js]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
=== tests/cases/compiler/mappedTypeCircularReferenceInAccessor.ts ===
2+
interface User {
3+
>User : Symbol(User, Decl(mappedTypeCircularReferenceInAccessor.ts, 0, 0))
4+
5+
firstName: string,
6+
>firstName : Symbol(User.firstName, Decl(mappedTypeCircularReferenceInAccessor.ts, 0, 16))
7+
8+
level: number,
9+
>level : Symbol(User.level, Decl(mappedTypeCircularReferenceInAccessor.ts, 1, 20))
10+
11+
get bestFriend(): User
12+
>bestFriend : Symbol(User.bestFriend, Decl(mappedTypeCircularReferenceInAccessor.ts, 2, 16), Decl(mappedTypeCircularReferenceInAccessor.ts, 3, 24))
13+
>User : Symbol(User, Decl(mappedTypeCircularReferenceInAccessor.ts, 0, 0))
14+
15+
set bestFriend(user: SerializablePartial<User>)
16+
>bestFriend : Symbol(User.bestFriend, Decl(mappedTypeCircularReferenceInAccessor.ts, 2, 16), Decl(mappedTypeCircularReferenceInAccessor.ts, 3, 24))
17+
>user : Symbol(user, Decl(mappedTypeCircularReferenceInAccessor.ts, 4, 17))
18+
>SerializablePartial : Symbol(SerializablePartial, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 137))
19+
>User : Symbol(User, Decl(mappedTypeCircularReferenceInAccessor.ts, 0, 0))
20+
}
21+
22+
type FilteredKeys<T> = { [K in keyof T]: T[K] extends number ? K : T[K] extends string ? K : T[K] extends boolean ? K : never }[keyof T];
23+
>FilteredKeys : Symbol(FilteredKeys, Decl(mappedTypeCircularReferenceInAccessor.ts, 5, 1))
24+
>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 18))
25+
>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 26))
26+
>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 18))
27+
>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 18))
28+
>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 26))
29+
>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 26))
30+
>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 18))
31+
>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 26))
32+
>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 26))
33+
>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 18))
34+
>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 26))
35+
>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 26))
36+
>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 18))
37+
38+
type SerializablePartial<T> = {
39+
>SerializablePartial : Symbol(SerializablePartial, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 137))
40+
>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 9, 25))
41+
42+
[K in FilteredKeys<T>]: T[K]
43+
>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 10, 3))
44+
>FilteredKeys : Symbol(FilteredKeys, Decl(mappedTypeCircularReferenceInAccessor.ts, 5, 1))
45+
>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 9, 25))
46+
>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 9, 25))
47+
>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 10, 3))
48+
49+
};
50+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
=== tests/cases/compiler/mappedTypeCircularReferenceInAccessor.ts ===
2+
interface User {
3+
firstName: string,
4+
>firstName : string
5+
6+
level: number,
7+
>level : number
8+
9+
get bestFriend(): User
10+
>bestFriend : User
11+
12+
set bestFriend(user: SerializablePartial<User>)
13+
>bestFriend : User
14+
>user : SerializablePartial<User>
15+
}
16+
17+
type FilteredKeys<T> = { [K in keyof T]: T[K] extends number ? K : T[K] extends string ? K : T[K] extends boolean ? K : never }[keyof T];
18+
>FilteredKeys : FilteredKeys<T>
19+
20+
type SerializablePartial<T> = {
21+
>SerializablePartial : SerializablePartial<T>
22+
23+
[K in FilteredKeys<T>]: T[K]
24+
};
25+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
interface User {
2+
firstName: string,
3+
level: number,
4+
get bestFriend(): User
5+
set bestFriend(user: SerializablePartial<User>)
6+
}
7+
8+
type FilteredKeys<T> = { [K in keyof T]: T[K] extends number ? K : T[K] extends string ? K : T[K] extends boolean ? K : never }[keyof T];
9+
10+
type SerializablePartial<T> = {
11+
[K in FilteredKeys<T>]: T[K]
12+
};

0 commit comments

Comments
 (0)