Skip to content

Commit 0e61018

Browse files
Andaristsandersn
andauthored
Avoid pulling object function property augmentations when resolving intersections' properties (#54753)
Co-authored-by: Nathan Shively-Sanders <[email protected]>
1 parent 24166a4 commit 0e61018

13 files changed

+322
-4
lines changed

src/compiler/checker.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13980,7 +13980,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1398013980
for (const current of type.types) {
1398113981
for (const prop of getPropertiesOfType(current)) {
1398213982
if (!members.has(prop.escapedName)) {
13983-
const combinedProp = getPropertyOfUnionOrIntersectionType(type, prop.escapedName);
13983+
const combinedProp = getPropertyOfUnionOrIntersectionType(type, prop.escapedName, /*skipObjectFunctionPropertyAugment*/ !!(type.flags & TypeFlags.Intersection));
1398413984
if (combinedProp) {
1398513985
members.set(prop.escapedName, combinedProp);
1398613986
}
@@ -14629,6 +14629,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1462914629
type.propertyCacheWithoutObjectFunctionPropertyAugment ||= createSymbolTable() :
1463014630
type.propertyCache ||= createSymbolTable();
1463114631
properties.set(name, property);
14632+
if (skipObjectFunctionPropertyAugment && !type.propertyCache?.get(name)) {
14633+
const properties = type.propertyCache ||= createSymbolTable();
14634+
properties.set(name, property);
14635+
}
1463214636
}
1463314637
}
1463414638
return property;
@@ -14771,7 +14775,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1477114775
}
1477214776
return getPropertyOfObjectType(globalObjectType, name);
1477314777
}
14774-
if (type.flags & TypeFlags.UnionOrIntersection) {
14778+
if (type.flags & TypeFlags.Intersection) {
14779+
const prop = getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name, /*skipObjectFunctionPropertyAugment*/ true);
14780+
if (prop) {
14781+
return prop;
14782+
}
14783+
if (!skipObjectFunctionPropertyAugment) {
14784+
return getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name, skipObjectFunctionPropertyAugment);
14785+
}
14786+
return undefined;
14787+
}
14788+
if (type.flags & TypeFlags.Union) {
1477514789
return getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name, skipObjectFunctionPropertyAugment);
1477614790
}
1477714791
return undefined;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//// [tests/cases/conformance/types/typeRelationships/assignmentCompatibility/intersectionIncludingPropFromGlobalAugmentation.ts] ////
2+
3+
=== intersectionIncludingPropFromGlobalAugmentation.ts ===
4+
// repro from https://github.com/microsoft/TypeScript/issues/54345
5+
6+
interface Test1 { toString: null | 'string'; }
7+
>Test1 : Symbol(Test1, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 0, 0))
8+
>toString : Symbol(Test1.toString, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 2, 17))
9+
10+
type Test2 = Test1 & { optional?: unknown };
11+
>Test2 : Symbol(Test2, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 2, 46))
12+
>Test1 : Symbol(Test1, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 0, 0))
13+
>optional : Symbol(optional, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 3, 22))
14+
15+
declare const source: Test1;
16+
>source : Symbol(source, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 4, 13))
17+
>Test1 : Symbol(Test1, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 0, 0))
18+
19+
const target: Test2 = { ...source };
20+
>target : Symbol(target, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 5, 5))
21+
>Test2 : Symbol(Test2, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 2, 46))
22+
>source : Symbol(source, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 4, 13))
23+
24+
const toString = target.toString;
25+
>toString : Symbol(toString, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 7, 5))
26+
>target.toString : Symbol(Test1.toString, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 2, 17))
27+
>target : Symbol(target, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 5, 5))
28+
>toString : Symbol(Test1.toString, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 2, 17))
29+
30+
const hasOwn = target.hasOwnProperty; // not an own member but it should still be accessible
31+
>hasOwn : Symbol(hasOwn, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 8, 5))
32+
>target.hasOwnProperty : Symbol(Object.hasOwnProperty, Decl(lib.es5.d.ts, --, --))
33+
>target : Symbol(target, Decl(intersectionIncludingPropFromGlobalAugmentation.ts, 5, 5))
34+
>hasOwnProperty : Symbol(Object.hasOwnProperty, Decl(lib.es5.d.ts, --, --))
35+
36+
export {}
37+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//// [tests/cases/conformance/types/typeRelationships/assignmentCompatibility/intersectionIncludingPropFromGlobalAugmentation.ts] ////
2+
3+
=== intersectionIncludingPropFromGlobalAugmentation.ts ===
4+
// repro from https://github.com/microsoft/TypeScript/issues/54345
5+
6+
interface Test1 { toString: null | 'string'; }
7+
>toString : "string" | null
8+
9+
type Test2 = Test1 & { optional?: unknown };
10+
>Test2 : Test1 & { optional?: unknown; }
11+
>optional : unknown
12+
13+
declare const source: Test1;
14+
>source : Test1
15+
16+
const target: Test2 = { ...source };
17+
>target : Test2
18+
>{ ...source } : { toString: "string" | null; }
19+
>source : Test1
20+
21+
const toString = target.toString;
22+
>toString : "string" | null
23+
>target.toString : "string" | null
24+
>target : Test2
25+
>toString : "string" | null
26+
27+
const hasOwn = target.hasOwnProperty; // not an own member but it should still be accessible
28+
>hasOwn : (v: PropertyKey) => boolean
29+
>target.hasOwnProperty : (v: PropertyKey) => boolean
30+
>target : Test2
31+
>hasOwnProperty : (v: PropertyKey) => boolean
32+
33+
export {}
34+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//// [tests/cases/compiler/intersectionWithConstructSignaturePrototypeResult.ts] ////
2+
3+
=== intersectionWithConstructSignaturePrototypeResult.ts ===
4+
declare class EmberObject {}
5+
>EmberObject : Symbol(EmberObject, Decl(intersectionWithConstructSignaturePrototypeResult.ts, 0, 0))
6+
7+
type PersonType = Readonly<typeof EmberObject> &
8+
>PersonType : Symbol(PersonType, Decl(intersectionWithConstructSignaturePrototypeResult.ts, 0, 28))
9+
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
10+
>EmberObject : Symbol(EmberObject, Decl(intersectionWithConstructSignaturePrototypeResult.ts, 0, 0))
11+
12+
(new (properties?: object) => {
13+
>properties : Symbol(properties, Decl(intersectionWithConstructSignaturePrototypeResult.ts, 3, 8))
14+
15+
firstName: string;
16+
>firstName : Symbol(firstName, Decl(intersectionWithConstructSignaturePrototypeResult.ts, 3, 33))
17+
18+
lastName: string;
19+
>lastName : Symbol(lastName, Decl(intersectionWithConstructSignaturePrototypeResult.ts, 4, 22))
20+
21+
} & EmberObject) &
22+
>EmberObject : Symbol(EmberObject, Decl(intersectionWithConstructSignaturePrototypeResult.ts, 0, 0))
23+
24+
(new (...args: any[]) => {
25+
>args : Symbol(args, Decl(intersectionWithConstructSignaturePrototypeResult.ts, 7, 8))
26+
27+
firstName: string;
28+
>firstName : Symbol(firstName, Decl(intersectionWithConstructSignaturePrototypeResult.ts, 7, 28))
29+
30+
lastName: string;
31+
>lastName : Symbol(lastName, Decl(intersectionWithConstructSignaturePrototypeResult.ts, 8, 22))
32+
33+
} & EmberObject);
34+
>EmberObject : Symbol(EmberObject, Decl(intersectionWithConstructSignaturePrototypeResult.ts, 0, 0))
35+
36+
type PersonPrototype = PersonType["prototype"];
37+
>PersonPrototype : Symbol(PersonPrototype, Decl(intersectionWithConstructSignaturePrototypeResult.ts, 10, 19))
38+
>PersonType : Symbol(PersonType, Decl(intersectionWithConstructSignaturePrototypeResult.ts, 0, 28))
39+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//// [tests/cases/compiler/intersectionWithConstructSignaturePrototypeResult.ts] ////
2+
3+
=== intersectionWithConstructSignaturePrototypeResult.ts ===
4+
declare class EmberObject {}
5+
>EmberObject : EmberObject
6+
7+
type PersonType = Readonly<typeof EmberObject> &
8+
>PersonType : Readonly<typeof EmberObject> & (new (properties?: object) => { firstName: string; lastName: string;} & EmberObject) & (new (...args: any[]) => { firstName: string; lastName: string;} & EmberObject)
9+
>EmberObject : typeof EmberObject
10+
11+
(new (properties?: object) => {
12+
>properties : object | undefined
13+
14+
firstName: string;
15+
>firstName : string
16+
17+
lastName: string;
18+
>lastName : string
19+
20+
} & EmberObject) &
21+
(new (...args: any[]) => {
22+
>args : any[]
23+
24+
firstName: string;
25+
>firstName : string
26+
27+
lastName: string;
28+
>lastName : string
29+
30+
} & EmberObject);
31+
32+
type PersonPrototype = PersonType["prototype"];
33+
>PersonPrototype : EmberObject
34+

0 commit comments

Comments
 (0)