Skip to content

Commit d5ef117

Browse files
authored
Copy consistient valueDeclarations on union/intersection symbols (microsoft#23190)
1 parent bcb5599 commit d5ef117

File tree

5 files changed

+142
-2
lines changed

5 files changed

+142
-2
lines changed

src/compiler/checker.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6677,7 +6677,15 @@ namespace ts {
66776677
let nameType: Type;
66786678
const propTypes: Type[] = [];
66796679
let first = true;
6680+
let commonValueDeclaration: Declaration;
6681+
let hasNonUniformValueDeclaration = false;
66806682
for (const prop of props) {
6683+
if (!commonValueDeclaration) {
6684+
commonValueDeclaration = prop.valueDeclaration;
6685+
}
6686+
else if (prop.valueDeclaration !== commonValueDeclaration) {
6687+
hasNonUniformValueDeclaration = true;
6688+
}
66816689
declarations = addRange(declarations, prop.declarations);
66826690
const type = getTypeOfSymbol(prop);
66836691
if (first) {
@@ -6694,6 +6702,9 @@ namespace ts {
66946702
}
66956703
const result = createSymbol(SymbolFlags.Property | commonFlags, name, syntheticFlag | checkFlags);
66966704
result.containingType = containingType;
6705+
if (!hasNonUniformValueDeclaration && commonValueDeclaration) {
6706+
result.valueDeclaration = commonValueDeclaration;
6707+
}
66976708
result.declarations = declarations;
66986709
result.nameType = nameType;
66996710
result.type = isUnion ? getUnionType(propTypes) : getIntersectionType(propTypes);
@@ -10774,13 +10785,14 @@ namespace ts {
1077410785
const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp);
1077510786
const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp);
1077610787
if (sourcePropFlags & ModifierFlags.Private || targetPropFlags & ModifierFlags.Private) {
10777-
if (getCheckFlags(sourceProp) & CheckFlags.ContainsPrivate) {
10788+
const hasDifferingDeclarations = sourceProp.valueDeclaration !== targetProp.valueDeclaration;
10789+
if (getCheckFlags(sourceProp) & CheckFlags.ContainsPrivate && hasDifferingDeclarations) {
1077810790
if (reportErrors) {
1077910791
reportError(Diagnostics.Property_0_has_conflicting_declarations_and_is_inaccessible_in_type_1, symbolToString(sourceProp), typeToString(source));
1078010792
}
1078110793
return Ternary.False;
1078210794
}
10783-
if (sourceProp.valueDeclaration !== targetProp.valueDeclaration) {
10795+
if (hasDifferingDeclarations) {
1078410796
if (reportErrors) {
1078510797
if (sourcePropFlags & ModifierFlags.Private && targetPropFlags & ModifierFlags.Private) {
1078610798
reportError(Diagnostics.Types_have_separate_declarations_of_a_private_property_0, symbolToString(targetProp));
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//// [doubleMixinConditionalTypeBaseClassWorks.ts]
2+
type Constructor = new (...args: any[]) => {};
3+
4+
const Mixin1 = <C extends Constructor>(Base: C) => class extends Base { private _fooPrivate: {}; }
5+
6+
type FooConstructor = typeof Mixin1 extends (a: Constructor) => infer Cls ? Cls : never;
7+
const Mixin2 = <C extends FooConstructor>(Base: C) => class extends Base {};
8+
9+
class C extends Mixin2(Mixin1(Object)) {}
10+
11+
//// [doubleMixinConditionalTypeBaseClassWorks.js]
12+
var __extends = (this && this.__extends) || (function () {
13+
var extendStatics = Object.setPrototypeOf ||
14+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
15+
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
16+
return function (d, b) {
17+
extendStatics(d, b);
18+
function __() { this.constructor = d; }
19+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
20+
};
21+
})();
22+
var Mixin1 = function (Base) { return /** @class */ (function (_super) {
23+
__extends(class_1, _super);
24+
function class_1() {
25+
return _super !== null && _super.apply(this, arguments) || this;
26+
}
27+
return class_1;
28+
}(Base)); };
29+
var Mixin2 = function (Base) { return /** @class */ (function (_super) {
30+
__extends(class_2, _super);
31+
function class_2() {
32+
return _super !== null && _super.apply(this, arguments) || this;
33+
}
34+
return class_2;
35+
}(Base)); };
36+
var C = /** @class */ (function (_super) {
37+
__extends(C, _super);
38+
function C() {
39+
return _super !== null && _super.apply(this, arguments) || this;
40+
}
41+
return C;
42+
}(Mixin2(Mixin1(Object))));
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
=== tests/cases/compiler/doubleMixinConditionalTypeBaseClassWorks.ts ===
2+
type Constructor = new (...args: any[]) => {};
3+
>Constructor : Symbol(Constructor, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 0, 0))
4+
>args : Symbol(args, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 0, 24))
5+
6+
const Mixin1 = <C extends Constructor>(Base: C) => class extends Base { private _fooPrivate: {}; }
7+
>Mixin1 : Symbol(Mixin1, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 5))
8+
>C : Symbol(C, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 16))
9+
>Constructor : Symbol(Constructor, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 0, 0))
10+
>Base : Symbol(Base, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 39))
11+
>C : Symbol(C, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 16))
12+
>Base : Symbol(Base, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 39))
13+
>_fooPrivate : Symbol((Anonymous class)._fooPrivate, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 71))
14+
15+
type FooConstructor = typeof Mixin1 extends (a: Constructor) => infer Cls ? Cls : never;
16+
>FooConstructor : Symbol(FooConstructor, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 98))
17+
>Mixin1 : Symbol(Mixin1, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 5))
18+
>a : Symbol(a, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 4, 45))
19+
>Constructor : Symbol(Constructor, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 0, 0))
20+
>Cls : Symbol(Cls, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 4, 69))
21+
>Cls : Symbol(Cls, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 4, 69))
22+
23+
const Mixin2 = <C extends FooConstructor>(Base: C) => class extends Base {};
24+
>Mixin2 : Symbol(Mixin2, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 5, 5))
25+
>C : Symbol(C, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 5, 16))
26+
>FooConstructor : Symbol(FooConstructor, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 98))
27+
>Base : Symbol(Base, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 5, 42))
28+
>C : Symbol(C, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 5, 16))
29+
>Base : Symbol(Base, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 5, 42))
30+
31+
class C extends Mixin2(Mixin1(Object)) {}
32+
>C : Symbol(C, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 5, 76))
33+
>Mixin2 : Symbol(Mixin2, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 5, 5))
34+
>Mixin1 : Symbol(Mixin1, Decl(doubleMixinConditionalTypeBaseClassWorks.ts, 2, 5))
35+
>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
36+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
=== tests/cases/compiler/doubleMixinConditionalTypeBaseClassWorks.ts ===
2+
type Constructor = new (...args: any[]) => {};
3+
>Constructor : Constructor
4+
>args : any[]
5+
6+
const Mixin1 = <C extends Constructor>(Base: C) => class extends Base { private _fooPrivate: {}; }
7+
>Mixin1 : <C extends Constructor>(Base: C) => { new (...args: any[]): (Anonymous class); prototype: <any>.(Anonymous class); } & C
8+
><C extends Constructor>(Base: C) => class extends Base { private _fooPrivate: {}; } : <C extends Constructor>(Base: C) => { new (...args: any[]): (Anonymous class); prototype: <any>.(Anonymous class); } & C
9+
>C : C
10+
>Constructor : Constructor
11+
>Base : C
12+
>C : C
13+
>class extends Base { private _fooPrivate: {}; } : { new (...args: any[]): (Anonymous class); prototype: <any>.(Anonymous class); } & C
14+
>Base : {}
15+
>_fooPrivate : {}
16+
17+
type FooConstructor = typeof Mixin1 extends (a: Constructor) => infer Cls ? Cls : never;
18+
>FooConstructor : { new (...args: any[]): <Constructor>.(Anonymous class); prototype: <any>.(Anonymous class); } & Constructor
19+
>Mixin1 : <C extends Constructor>(Base: C) => { new (...args: any[]): (Anonymous class); prototype: <any>.(Anonymous class); } & C
20+
>a : Constructor
21+
>Constructor : Constructor
22+
>Cls : Cls
23+
>Cls : Cls
24+
25+
const Mixin2 = <C extends FooConstructor>(Base: C) => class extends Base {};
26+
>Mixin2 : <C extends { new (...args: any[]): <Constructor>.(Anonymous class); prototype: <any>.(Anonymous class); } & Constructor>(Base: C) => { new (...args: any[]): (Anonymous class); prototype: <any>.(Anonymous class); } & C
27+
><C extends FooConstructor>(Base: C) => class extends Base {} : <C extends { new (...args: any[]): <Constructor>.(Anonymous class); prototype: <any>.(Anonymous class); } & Constructor>(Base: C) => { new (...args: any[]): (Anonymous class); prototype: <any>.(Anonymous class); } & C
28+
>C : C
29+
>FooConstructor : { new (...args: any[]): <Constructor>.(Anonymous class); prototype: <any>.(Anonymous class); } & Constructor
30+
>Base : C
31+
>C : C
32+
>class extends Base {} : { new (...args: any[]): (Anonymous class); prototype: <any>.(Anonymous class); } & C
33+
>Base : <Constructor>.(Anonymous class)
34+
35+
class C extends Mixin2(Mixin1(Object)) {}
36+
>C : C
37+
>Mixin2(Mixin1(Object)) : <{ new (...args: any[]): <ObjectConstructor>.(Anonymous class); prototype: <any>.(Anonymous class); } & ObjectConstructor>.(Anonymous class) & <ObjectConstructor>.(Anonymous class) & Object
38+
>Mixin2 : <C extends { new (...args: any[]): <Constructor>.(Anonymous class); prototype: <any>.(Anonymous class); } & Constructor>(Base: C) => { new (...args: any[]): (Anonymous class); prototype: <any>.(Anonymous class); } & C
39+
>Mixin1(Object) : { new (...args: any[]): <ObjectConstructor>.(Anonymous class); prototype: <any>.(Anonymous class); } & ObjectConstructor
40+
>Mixin1 : <C extends Constructor>(Base: C) => { new (...args: any[]): (Anonymous class); prototype: <any>.(Anonymous class); } & C
41+
>Object : ObjectConstructor
42+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
type Constructor = new (...args: any[]) => {};
2+
3+
const Mixin1 = <C extends Constructor>(Base: C) => class extends Base { private _fooPrivate: {}; }
4+
5+
type FooConstructor = typeof Mixin1 extends (a: Constructor) => infer Cls ? Cls : never;
6+
const Mixin2 = <C extends FooConstructor>(Base: C) => class extends Base {};
7+
8+
class C extends Mixin2(Mixin1(Object)) {}

0 commit comments

Comments
 (0)