From ed6f7a823daae3ea13388aeadaeac9639171c576 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 9 Feb 2022 10:03:34 -0800 Subject: [PATCH] Avoid pulling on setter type when only getter type is needed to break circularity --- src/compiler/checker.ts | 10 ++-- .../mappedTypeCircularReferenceInAccessor.js | 16 ++++++ ...pedTypeCircularReferenceInAccessor.symbols | 50 +++++++++++++++++++ ...appedTypeCircularReferenceInAccessor.types | 25 ++++++++++ .../mappedTypeCircularReferenceInAccessor.ts | 12 +++++ 5 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 tests/baselines/reference/mappedTypeCircularReferenceInAccessor.js create mode 100644 tests/baselines/reference/mappedTypeCircularReferenceInAccessor.symbols create mode 100644 tests/baselines/reference/mappedTypeCircularReferenceInAccessor.types create mode 100644 tests/cases/compiler/mappedTypeCircularReferenceInAccessor.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2201a3aa30264..e218766a708e3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9511,11 +9511,12 @@ namespace ts { const getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor); const setter = getDeclarationOfKind(symbol, SyntaxKind.SetAccessor); - const setterType = getAnnotatedAccessorType(setter); - // For write operations, prioritize type annotations on the setter - if (writing && setterType) { - return instantiateTypeIfNeeded(setterType, symbol); + if (writing) { + const setterType = getAnnotatedAccessorType(setter); + if (setterType) { + return instantiateTypeIfNeeded(setterType, symbol); + } } // Else defer to the getter type @@ -9533,6 +9534,7 @@ namespace ts { } // If the user didn't specify a return type, try to use the set-accessor's parameter type. + const setterType = getAnnotatedAccessorType(setter); if (setterType) { return setterType; } diff --git a/tests/baselines/reference/mappedTypeCircularReferenceInAccessor.js b/tests/baselines/reference/mappedTypeCircularReferenceInAccessor.js new file mode 100644 index 0000000000000..f48a16541cdda --- /dev/null +++ b/tests/baselines/reference/mappedTypeCircularReferenceInAccessor.js @@ -0,0 +1,16 @@ +//// [mappedTypeCircularReferenceInAccessor.ts] +interface User { + firstName: string, + level: number, + get bestFriend(): User + set bestFriend(user: SerializablePartial) +} + +type FilteredKeys = { [K in keyof T]: T[K] extends number ? K : T[K] extends string ? K : T[K] extends boolean ? K : never }[keyof T]; + +type SerializablePartial = { + [K in FilteredKeys]: T[K] +}; + + +//// [mappedTypeCircularReferenceInAccessor.js] diff --git a/tests/baselines/reference/mappedTypeCircularReferenceInAccessor.symbols b/tests/baselines/reference/mappedTypeCircularReferenceInAccessor.symbols new file mode 100644 index 0000000000000..9b7be7485a1af --- /dev/null +++ b/tests/baselines/reference/mappedTypeCircularReferenceInAccessor.symbols @@ -0,0 +1,50 @@ +=== tests/cases/compiler/mappedTypeCircularReferenceInAccessor.ts === +interface User { +>User : Symbol(User, Decl(mappedTypeCircularReferenceInAccessor.ts, 0, 0)) + + firstName: string, +>firstName : Symbol(User.firstName, Decl(mappedTypeCircularReferenceInAccessor.ts, 0, 16)) + + level: number, +>level : Symbol(User.level, Decl(mappedTypeCircularReferenceInAccessor.ts, 1, 20)) + + get bestFriend(): User +>bestFriend : Symbol(User.bestFriend, Decl(mappedTypeCircularReferenceInAccessor.ts, 2, 16), Decl(mappedTypeCircularReferenceInAccessor.ts, 3, 24)) +>User : Symbol(User, Decl(mappedTypeCircularReferenceInAccessor.ts, 0, 0)) + + set bestFriend(user: SerializablePartial) +>bestFriend : Symbol(User.bestFriend, Decl(mappedTypeCircularReferenceInAccessor.ts, 2, 16), Decl(mappedTypeCircularReferenceInAccessor.ts, 3, 24)) +>user : Symbol(user, Decl(mappedTypeCircularReferenceInAccessor.ts, 4, 17)) +>SerializablePartial : Symbol(SerializablePartial, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 137)) +>User : Symbol(User, Decl(mappedTypeCircularReferenceInAccessor.ts, 0, 0)) +} + +type FilteredKeys = { [K in keyof T]: T[K] extends number ? K : T[K] extends string ? K : T[K] extends boolean ? K : never }[keyof T]; +>FilteredKeys : Symbol(FilteredKeys, Decl(mappedTypeCircularReferenceInAccessor.ts, 5, 1)) +>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 18)) +>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 26)) +>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 18)) +>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 18)) +>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 26)) +>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 26)) +>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 18)) +>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 26)) +>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 26)) +>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 18)) +>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 26)) +>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 26)) +>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 18)) + +type SerializablePartial = { +>SerializablePartial : Symbol(SerializablePartial, Decl(mappedTypeCircularReferenceInAccessor.ts, 7, 137)) +>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 9, 25)) + + [K in FilteredKeys]: T[K] +>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 10, 3)) +>FilteredKeys : Symbol(FilteredKeys, Decl(mappedTypeCircularReferenceInAccessor.ts, 5, 1)) +>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 9, 25)) +>T : Symbol(T, Decl(mappedTypeCircularReferenceInAccessor.ts, 9, 25)) +>K : Symbol(K, Decl(mappedTypeCircularReferenceInAccessor.ts, 10, 3)) + +}; + diff --git a/tests/baselines/reference/mappedTypeCircularReferenceInAccessor.types b/tests/baselines/reference/mappedTypeCircularReferenceInAccessor.types new file mode 100644 index 0000000000000..0f713d6f1c08d --- /dev/null +++ b/tests/baselines/reference/mappedTypeCircularReferenceInAccessor.types @@ -0,0 +1,25 @@ +=== tests/cases/compiler/mappedTypeCircularReferenceInAccessor.ts === +interface User { + firstName: string, +>firstName : string + + level: number, +>level : number + + get bestFriend(): User +>bestFriend : User + + set bestFriend(user: SerializablePartial) +>bestFriend : User +>user : SerializablePartial +} + +type FilteredKeys = { [K in keyof T]: T[K] extends number ? K : T[K] extends string ? K : T[K] extends boolean ? K : never }[keyof T]; +>FilteredKeys : FilteredKeys + +type SerializablePartial = { +>SerializablePartial : SerializablePartial + + [K in FilteredKeys]: T[K] +}; + diff --git a/tests/cases/compiler/mappedTypeCircularReferenceInAccessor.ts b/tests/cases/compiler/mappedTypeCircularReferenceInAccessor.ts new file mode 100644 index 0000000000000..82138b5ff0aac --- /dev/null +++ b/tests/cases/compiler/mappedTypeCircularReferenceInAccessor.ts @@ -0,0 +1,12 @@ +interface User { + firstName: string, + level: number, + get bestFriend(): User + set bestFriend(user: SerializablePartial) +} + +type FilteredKeys = { [K in keyof T]: T[K] extends number ? K : T[K] extends string ? K : T[K] extends boolean ? K : never }[keyof T]; + +type SerializablePartial = { + [K in FilteredKeys]: T[K] +};