From 0c6404b04ddc9e680155e538e6f3507164d376ee Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 30 Apr 2020 13:04:32 -0700 Subject: [PATCH 1/2] Property handle private/protected properties in unions of object types --- src/compiler/checker.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f24f8b93d1ab5..227d29bbf977e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10527,7 +10527,6 @@ namespace ts { let propSet: Map | undefined; let indexTypes: Type[] | undefined; const isUnion = containingType.flags & TypeFlags.Union; - const excludeModifiers = isUnion ? ModifierFlags.NonPublicAccessibilityModifier : 0; // Flags we want to propagate to the result if they exist in all source symbols let optionalFlag = isUnion ? SymbolFlags.None : SymbolFlags.Optional; let syntheticFlag = CheckFlags.SyntheticMethod; @@ -10537,7 +10536,7 @@ namespace ts { if (!(type === errorType || type.flags & TypeFlags.Never)) { const prop = getPropertyOfType(type, name); const modifiers = prop ? getDeclarationModifierFlagsFromSymbol(prop) : 0; - if (prop && !(modifiers & excludeModifiers)) { + if (prop) { if (isUnion) { optionalFlag |= (prop.flags & SymbolFlags.Optional); } @@ -10582,7 +10581,9 @@ namespace ts { } } } - if (!singleProp) { + if (!singleProp || isUnion && (propSet || checkFlags & CheckFlags.Partial) && checkFlags & (CheckFlags.ContainsPrivate | CheckFlags.ContainsProtected)) { + // No property was found, or, in a union, a property has a private or protected declaration in one + // constituent, but is missing or has a different declaration in another constituent. return undefined; } if (!propSet && !(checkFlags & CheckFlags.ReadPartial) && !indexTypes) { From 0f76e2fc5f48c2b5a5027401b775d3db92b4d289 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 30 Apr 2020 13:07:45 -0700 Subject: [PATCH 2/2] Add regression test --- .../reference/privatePropertyInUnion.js | 24 ++++++++++++++ .../reference/privatePropertyInUnion.symbols | 32 +++++++++++++++++++ .../reference/privatePropertyInUnion.types | 20 ++++++++++++ .../cases/compiler/privatePropertyInUnion.ts | 15 +++++++++ 4 files changed, 91 insertions(+) create mode 100644 tests/baselines/reference/privatePropertyInUnion.js create mode 100644 tests/baselines/reference/privatePropertyInUnion.symbols create mode 100644 tests/baselines/reference/privatePropertyInUnion.types create mode 100644 tests/cases/compiler/privatePropertyInUnion.ts diff --git a/tests/baselines/reference/privatePropertyInUnion.js b/tests/baselines/reference/privatePropertyInUnion.js new file mode 100644 index 0000000000000..f4208e51fe4af --- /dev/null +++ b/tests/baselines/reference/privatePropertyInUnion.js @@ -0,0 +1,24 @@ +//// [privatePropertyInUnion.ts] +// Repro from #38236 + +type Type = string | object; + +class SyncableObject { + private foo: unknown; +} + +interface SyncableRef {} + +interface ISyncableObject extends SyncableObject {} + +type __ValueDescriptorType = T extends ISyncableObject ? SyncableRef : T; + + +//// [privatePropertyInUnion.js] +"use strict"; +// Repro from #38236 +var SyncableObject = /** @class */ (function () { + function SyncableObject() { + } + return SyncableObject; +}()); diff --git a/tests/baselines/reference/privatePropertyInUnion.symbols b/tests/baselines/reference/privatePropertyInUnion.symbols new file mode 100644 index 0000000000000..01b4fdea82529 --- /dev/null +++ b/tests/baselines/reference/privatePropertyInUnion.symbols @@ -0,0 +1,32 @@ +=== tests/cases/compiler/privatePropertyInUnion.ts === +// Repro from #38236 + +type Type = string | object; +>Type : Symbol(Type, Decl(privatePropertyInUnion.ts, 0, 0)) + +class SyncableObject { +>SyncableObject : Symbol(SyncableObject, Decl(privatePropertyInUnion.ts, 2, 28)) + + private foo: unknown; +>foo : Symbol(SyncableObject.foo, Decl(privatePropertyInUnion.ts, 4, 22)) +} + +interface SyncableRef {} +>SyncableRef : Symbol(SyncableRef, Decl(privatePropertyInUnion.ts, 6, 1)) +>T : Symbol(T, Decl(privatePropertyInUnion.ts, 8, 22)) +>ISyncableObject : Symbol(ISyncableObject, Decl(privatePropertyInUnion.ts, 8, 51)) + +interface ISyncableObject extends SyncableObject {} +>ISyncableObject : Symbol(ISyncableObject, Decl(privatePropertyInUnion.ts, 8, 51)) +>T : Symbol(T, Decl(privatePropertyInUnion.ts, 10, 26)) +>SyncableObject : Symbol(SyncableObject, Decl(privatePropertyInUnion.ts, 2, 28)) + +type __ValueDescriptorType = T extends ISyncableObject ? SyncableRef : T; +>__ValueDescriptorType : Symbol(__ValueDescriptorType, Decl(privatePropertyInUnion.ts, 10, 63)) +>T : Symbol(T, Decl(privatePropertyInUnion.ts, 12, 27)) +>T : Symbol(T, Decl(privatePropertyInUnion.ts, 12, 27)) +>ISyncableObject : Symbol(ISyncableObject, Decl(privatePropertyInUnion.ts, 8, 51)) +>SyncableRef : Symbol(SyncableRef, Decl(privatePropertyInUnion.ts, 6, 1)) +>T : Symbol(T, Decl(privatePropertyInUnion.ts, 12, 27)) +>T : Symbol(T, Decl(privatePropertyInUnion.ts, 12, 27)) + diff --git a/tests/baselines/reference/privatePropertyInUnion.types b/tests/baselines/reference/privatePropertyInUnion.types new file mode 100644 index 0000000000000..1bc4ea394773a --- /dev/null +++ b/tests/baselines/reference/privatePropertyInUnion.types @@ -0,0 +1,20 @@ +=== tests/cases/compiler/privatePropertyInUnion.ts === +// Repro from #38236 + +type Type = string | object; +>Type : string | object + +class SyncableObject { +>SyncableObject : SyncableObject + + private foo: unknown; +>foo : unknown +} + +interface SyncableRef {} + +interface ISyncableObject extends SyncableObject {} + +type __ValueDescriptorType = T extends ISyncableObject ? SyncableRef : T; +>__ValueDescriptorType : __ValueDescriptorType + diff --git a/tests/cases/compiler/privatePropertyInUnion.ts b/tests/cases/compiler/privatePropertyInUnion.ts new file mode 100644 index 0000000000000..59069cb5de1ef --- /dev/null +++ b/tests/cases/compiler/privatePropertyInUnion.ts @@ -0,0 +1,15 @@ +// @strict: true + +// Repro from #38236 + +type Type = string | object; + +class SyncableObject { + private foo: unknown; +} + +interface SyncableRef {} + +interface ISyncableObject extends SyncableObject {} + +type __ValueDescriptorType = T extends ISyncableObject ? SyncableRef : T;