diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fa485b68a92..0819ece651e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6677,7 +6677,15 @@ namespace ts { let nameType: Type; const propTypes: Type[] = []; let first = true; + let commonValueDeclaration: Declaration; + let hasNonUniformValueDeclaration = false; for (const prop of props) { + if (!commonValueDeclaration) { + commonValueDeclaration = prop.valueDeclaration; + } + else if (prop.valueDeclaration !== commonValueDeclaration) { + hasNonUniformValueDeclaration = true; + } declarations = addRange(declarations, prop.declarations); const type = getTypeOfSymbol(prop); if (first) { @@ -6694,6 +6702,9 @@ namespace ts { } const result = createSymbol(SymbolFlags.Property | commonFlags, name, syntheticFlag | checkFlags); result.containingType = containingType; + if (!hasNonUniformValueDeclaration && commonValueDeclaration) { + result.valueDeclaration = commonValueDeclaration; + } result.declarations = declarations; result.nameType = nameType; result.type = isUnion ? getUnionType(propTypes) : getIntersectionType(propTypes); @@ -10774,13 +10785,14 @@ namespace ts { const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp); const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp); if (sourcePropFlags & ModifierFlags.Private || targetPropFlags & ModifierFlags.Private) { - if (getCheckFlags(sourceProp) & CheckFlags.ContainsPrivate) { + const hasDifferingDeclarations = sourceProp.valueDeclaration !== targetProp.valueDeclaration; + if (getCheckFlags(sourceProp) & CheckFlags.ContainsPrivate && hasDifferingDeclarations) { if (reportErrors) { reportError(Diagnostics.Property_0_has_conflicting_declarations_and_is_inaccessible_in_type_1, symbolToString(sourceProp), typeToString(source)); } return Ternary.False; } - if (sourceProp.valueDeclaration !== targetProp.valueDeclaration) { + if (hasDifferingDeclarations) { if (reportErrors) { if (sourcePropFlags & ModifierFlags.Private && targetPropFlags & ModifierFlags.Private) { reportError(Diagnostics.Types_have_separate_declarations_of_a_private_property_0, symbolToString(targetProp)); diff --git a/tests/baselines/reference/doubleMixinConditionalTypeBaseClassWorks.js b/tests/baselines/reference/doubleMixinConditionalTypeBaseClassWorks.js new file mode 100644 index 00000000000..6ea7a46bb68 --- /dev/null +++ b/tests/baselines/reference/doubleMixinConditionalTypeBaseClassWorks.js @@ -0,0 +1,42 @@ +//// [doubleMixinConditionalTypeBaseClassWorks.ts] +type Constructor = new (...args: any[]) => {}; + +const Mixin1 = (Base: C) => class extends Base { private _fooPrivate: {}; } + +type FooConstructor = typeof Mixin1 extends (a: Constructor) => infer Cls ? Cls : never; +const Mixin2 = (Base: C) => class extends Base {}; + +class C extends Mixin2(Mixin1(Object)) {} + +//// [doubleMixinConditionalTypeBaseClassWorks.js] +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var Mixin1 = function (Base) { return /** @class */ (function (_super) { + __extends(class_1, _super); + function class_1() { + return _super !== null && _super.apply(this, arguments) || this; + } + return class_1; +}(Base)); }; +var Mixin2 = function (Base) { return /** @class */ (function (_super) { + __extends(class_2, _super); + function class_2() { + return _super !== null && _super.apply(this, arguments) || this; + } + return class_2; +}(Base)); }; +var C = /** @class */ (function (_super) { + __extends(C, _super); + function C() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C; +}(Mixin2(Mixin1(Object)))); diff --git a/tests/baselines/reference/doubleMixinConditionalTypeBaseClassWorks.symbols b/tests/baselines/reference/doubleMixinConditionalTypeBaseClassWorks.symbols new file mode 100644 index 00000000000..f1f0187a7eb --- /dev/null +++ b/tests/baselines/reference/doubleMixinConditionalTypeBaseClassWorks.symbols @@ -0,0 +1,36 @@ +=== tests/cases/compiler/doubleMixinConditionalTypeBaseClassWorks.ts === +type Constructor = new (...args: any[]) => {}; +>Constructor : Symbol(Constructor, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 0, 0)) +>args : Symbol(args, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 0, 24)) + +const Mixin1 = (Base: C) => class extends Base { private _fooPrivate: {}; } +>Mixin1 : Symbol(Mixin1, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 5)) +>C : Symbol(C, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 16)) +>Constructor : Symbol(Constructor, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 0, 0)) +>Base : Symbol(Base, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 39)) +>C : Symbol(C, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 16)) +>Base : Symbol(Base, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 39)) +>_fooPrivate : Symbol((Anonymous class)._fooPrivate, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 71)) + +type FooConstructor = typeof Mixin1 extends (a: Constructor) => infer Cls ? Cls : never; +>FooConstructor : Symbol(FooConstructor, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 98)) +>Mixin1 : Symbol(Mixin1, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 5)) +>a : Symbol(a, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 4, 45)) +>Constructor : Symbol(Constructor, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 0, 0)) +>Cls : Symbol(Cls, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 4, 69)) +>Cls : Symbol(Cls, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 4, 69)) + +const Mixin2 = (Base: C) => class extends Base {}; +>Mixin2 : Symbol(Mixin2, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 5, 5)) +>C : Symbol(C, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 5, 16)) +>FooConstructor : Symbol(FooConstructor, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 98)) +>Base : Symbol(Base, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 5, 42)) +>C : Symbol(C, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 5, 16)) +>Base : Symbol(Base, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 5, 42)) + +class C extends Mixin2(Mixin1(Object)) {} +>C : Symbol(C, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 5, 76)) +>Mixin2 : Symbol(Mixin2, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 5, 5)) +>Mixin1 : Symbol(Mixin1, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 5)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + diff --git a/tests/baselines/reference/doubleMixinConditionalTypeBaseClassWorks.types b/tests/baselines/reference/doubleMixinConditionalTypeBaseClassWorks.types new file mode 100644 index 00000000000..5fd92f6e2eb --- /dev/null +++ b/tests/baselines/reference/doubleMixinConditionalTypeBaseClassWorks.types @@ -0,0 +1,42 @@ +=== tests/cases/compiler/doubleMixinConditionalTypeBaseClassWorks.ts === +type Constructor = new (...args: any[]) => {}; +>Constructor : Constructor +>args : any[] + +const Mixin1 = (Base: C) => class extends Base { private _fooPrivate: {}; } +>Mixin1 : (Base: C) => { new (...args: any[]): (Anonymous class); prototype: .(Anonymous class); } & C +>(Base: C) => class extends Base { private _fooPrivate: {}; } : (Base: C) => { new (...args: any[]): (Anonymous class); prototype: .(Anonymous class); } & C +>C : C +>Constructor : Constructor +>Base : C +>C : C +>class extends Base { private _fooPrivate: {}; } : { new (...args: any[]): (Anonymous class); prototype: .(Anonymous class); } & C +>Base : {} +>_fooPrivate : {} + +type FooConstructor = typeof Mixin1 extends (a: Constructor) => infer Cls ? Cls : never; +>FooConstructor : { new (...args: any[]): .(Anonymous class); prototype: .(Anonymous class); } & Constructor +>Mixin1 : (Base: C) => { new (...args: any[]): (Anonymous class); prototype: .(Anonymous class); } & C +>a : Constructor +>Constructor : Constructor +>Cls : Cls +>Cls : Cls + +const Mixin2 = (Base: C) => class extends Base {}; +>Mixin2 : .(Anonymous class); prototype: .(Anonymous class); } & Constructor>(Base: C) => { new (...args: any[]): (Anonymous class); prototype: .(Anonymous class); } & C +>(Base: C) => class extends Base {} : .(Anonymous class); prototype: .(Anonymous class); } & Constructor>(Base: C) => { new (...args: any[]): (Anonymous class); prototype: .(Anonymous class); } & C +>C : C +>FooConstructor : { new (...args: any[]): .(Anonymous class); prototype: .(Anonymous class); } & Constructor +>Base : C +>C : C +>class extends Base {} : { new (...args: any[]): (Anonymous class); prototype: .(Anonymous class); } & C +>Base : .(Anonymous class) + +class C extends Mixin2(Mixin1(Object)) {} +>C : C +>Mixin2(Mixin1(Object)) : <{ new (...args: any[]): .(Anonymous class); prototype: .(Anonymous class); } & ObjectConstructor>.(Anonymous class) & .(Anonymous class) & Object +>Mixin2 : .(Anonymous class); prototype: .(Anonymous class); } & Constructor>(Base: C) => { new (...args: any[]): (Anonymous class); prototype: .(Anonymous class); } & C +>Mixin1(Object) : { new (...args: any[]): .(Anonymous class); prototype: .(Anonymous class); } & ObjectConstructor +>Mixin1 : (Base: C) => { new (...args: any[]): (Anonymous class); prototype: .(Anonymous class); } & C +>Object : ObjectConstructor + diff --git a/tests/cases/compiler/doubleMixinConditionalTypeBaseClassWorks.ts b/tests/cases/compiler/doubleMixinConditionalTypeBaseClassWorks.ts new file mode 100644 index 00000000000..616e5f56b3f --- /dev/null +++ b/tests/cases/compiler/doubleMixinConditionalTypeBaseClassWorks.ts @@ -0,0 +1,8 @@ +type Constructor = new (...args: any[]) => {}; + +const Mixin1 = (Base: C) => class extends Base { private _fooPrivate: {}; } + +type FooConstructor = typeof Mixin1 extends (a: Constructor) => infer Cls ? Cls : never; +const Mixin2 = (Base: C) => class extends Base {}; + +class C extends Mixin2(Mixin1(Object)) {} \ No newline at end of file