Skip to content

Commit dce7fca

Browse files
authored
Merge pull request #15033 from Microsoft/emptyObjectIntersection
Remove empty object types from intersection types
2 parents bb8862f + 0b5284d commit dce7fca

14 files changed

+327
-58
lines changed

src/compiler/checker.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6906,6 +6906,8 @@ namespace ts {
69066906
containsString?: boolean;
69076907
containsNumber?: boolean;
69086908
containsStringOrNumberLiteral?: boolean;
6909+
containsObjectType?: boolean;
6910+
containsEmptyObject?: boolean;
69096911
unionIndex?: number;
69106912
}
69116913

@@ -7101,7 +7103,13 @@ namespace ts {
71017103
else if (type.flags & TypeFlags.Any) {
71027104
typeSet.containsAny = true;
71037105
}
7106+
else if (getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(type)) {
7107+
typeSet.containsEmptyObject = true;
7108+
}
71047109
else if (!(type.flags & TypeFlags.Never) && (strictNullChecks || !(type.flags & TypeFlags.Nullable)) && !contains(typeSet, type)) {
7110+
if (type.flags & TypeFlags.Object) {
7111+
typeSet.containsObjectType = true;
7112+
}
71057113
if (type.flags & TypeFlags.Union && typeSet.unionIndex === undefined) {
71067114
typeSet.unionIndex = typeSet.length;
71077115
}
@@ -7139,6 +7147,9 @@ namespace ts {
71397147
if (typeSet.containsAny) {
71407148
return anyType;
71417149
}
7150+
if (typeSet.containsEmptyObject && !typeSet.containsObjectType) {
7151+
typeSet.push(emptyObjectType);
7152+
}
71427153
if (typeSet.length === 1) {
71437154
return typeSet[0];
71447155
}
@@ -8309,6 +8320,18 @@ namespace ts {
83098320
}
83108321
}
83118322

8323+
function isEmptyResolvedType(t: ResolvedType) {
8324+
return t.properties.length === 0 &&
8325+
t.callSignatures.length === 0 &&
8326+
t.constructSignatures.length === 0 &&
8327+
!t.stringIndexInfo &&
8328+
!t.numberIndexInfo;
8329+
}
8330+
8331+
function isEmptyObjectType(type: Type) {
8332+
return type.flags & TypeFlags.Object && isEmptyResolvedType(resolveStructuredTypeMembers(<ObjectType>type));
8333+
}
8334+
83128335
function isEnumTypeRelatedTo(source: EnumType, target: EnumType, errorReporter?: ErrorReporter) {
83138336
if (source === target) {
83148337
return true;
@@ -8644,18 +8667,6 @@ namespace ts {
86448667
return false;
86458668
}
86468669

8647-
function isEmptyResolvedType(t: ResolvedType) {
8648-
return t.properties.length === 0 &&
8649-
t.callSignatures.length === 0 &&
8650-
t.constructSignatures.length === 0 &&
8651-
!t.stringIndexInfo &&
8652-
!t.numberIndexInfo;
8653-
}
8654-
8655-
function isEmptyObjectType(type: Type) {
8656-
return type.flags & TypeFlags.Object && isEmptyResolvedType(resolveStructuredTypeMembers(<ObjectType>type));
8657-
}
8658-
86598670
function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean {
86608671
if (maybeTypeOfKind(target, TypeFlags.Object) && !(getObjectFlags(target) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) {
86618672
const isComparingJsxAttributes = !!(source.flags & TypeFlags.JsxAttributes);

tests/baselines/reference/declarationEmitPromise.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,5 @@ exports.runSampleBreaks = runSampleBreaks;
5959
export declare class bluebird<T> {
6060
static all: Array<bluebird<any>>;
6161
}
62-
export declare function runSampleWorks<A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>): Promise<(<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T) & {}>;
62+
export declare function runSampleWorks<A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>): Promise<(<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T)>;
6363
export declare function runSampleBreaks<A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>): Promise<(<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T)>;

tests/baselines/reference/declarationEmitPromise.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export class bluebird<T> {
1010
}
1111

1212
export async function runSampleWorks<A, B, C, D, E>(
13-
>runSampleWorks : <A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>) => Promise<(<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T) & {}>
13+
>runSampleWorks : <A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>) => Promise<(<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T)>
1414
>A : A
1515
>B : B
1616
>C : C
@@ -85,13 +85,13 @@ export async function runSampleWorks<A, B, C, D, E>(
8585
>result : any
8686

8787
let rfunc: typeof func & {} = func as any; // <- This is the only difference
88-
>rfunc : (<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T) & {}
88+
>rfunc : <T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T
8989
>func : <T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T
9090
>func as any : any
9191
>func : <T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T
9292

9393
return rfunc
94-
>rfunc : (<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T) & {}
94+
>rfunc : <T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T
9595
}
9696

9797
export async function runSampleBreaks<A, B, C, D, E>(

tests/baselines/reference/genericDefaults.types

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,7 @@ declare function f12<T, U = T & B>(a?: T, b?: U): [T, U];
10941094

10951095
// inference
10961096
f12();
1097-
>f12() : [{}, {} & B]
1097+
>f12() : [{}, B]
10981098
>f12 : <T, U = T & B>(a?: T, b?: U) => [T, U]
10991099

11001100
f12(a);
@@ -1856,7 +1856,7 @@ declare function f19<T = U, U = T & B>(a?: T, b?: U): [T, U];
18561856

18571857
// inference
18581858
f19();
1859-
>f19() : [{}, {} & B]
1859+
>f19() : [{}, B]
18601860
>f19 : <T = U, U = T & B>(a?: T, b?: U) => [T, U]
18611861

18621862
f19(a);
@@ -1950,11 +1950,11 @@ declare function f20<T, U = V, V = U & C>(a?: T, b?: U, c?: V): [T, U, V];
19501950

19511951
// inference
19521952
f20();
1953-
>f20() : [{}, {}, {} & C]
1953+
>f20() : [{}, {}, C]
19541954
>f20 : <T, U = V, V = U & C>(a?: T, b?: U, c?: V) => [T, U, V]
19551955

19561956
f20(a);
1957-
>f20(a) : [A, {}, {} & C]
1957+
>f20(a) : [A, {}, C]
19581958
>f20 : <T, U = V, V = U & C>(a?: T, b?: U, c?: V) => [T, U, V]
19591959
>a : A
19601960

@@ -1973,25 +1973,25 @@ f20(a, b, c);
19731973

19741974
// no inference, partially supplied
19751975
f20<A>();
1976-
>f20<A>() : [A, {}, {} & C]
1976+
>f20<A>() : [A, {}, C]
19771977
>f20 : <T, U = V, V = U & C>(a?: T, b?: U, c?: V) => [T, U, V]
19781978
>A : A
19791979

19801980
f20<A>(a);
1981-
>f20<A>(a) : [A, {}, {} & C]
1981+
>f20<A>(a) : [A, {}, C]
19821982
>f20 : <T, U = V, V = U & C>(a?: T, b?: U, c?: V) => [T, U, V]
19831983
>A : A
19841984
>a : A
19851985

19861986
f20<A>(a, b);
1987-
>f20<A>(a, b) : [A, {}, {} & C]
1987+
>f20<A>(a, b) : [A, {}, C]
19881988
>f20 : <T, U = V, V = U & C>(a?: T, b?: U, c?: V) => [T, U, V]
19891989
>A : A
19901990
>a : A
19911991
>b : B
19921992

19931993
f20<A>(a, b, bc);
1994-
>f20<A>(a, b, bc) : [A, {}, {} & C]
1994+
>f20<A>(a, b, bc) : [A, {}, C]
19951995
>f20 : <T, U = V, V = U & C>(a?: T, b?: U, c?: V) => [T, U, V]
19961996
>A : A
19971997
>a : A
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//// [intersectionsAndEmptyObjects.ts]
2+
// Empty object type literals are removed from intersections types
3+
// that contain other object types
4+
5+
type A = { a: number };
6+
type B = { b: string };
7+
type C = {};
8+
9+
let x01: A & B;
10+
let x02: A & C;
11+
let x03: B & C;
12+
let x04: A & B & C;
13+
let x05: string & C;
14+
let x06: C & string;
15+
let x07: C;
16+
let x08: C & {};
17+
let x09: {} & A & {} & B & {} & C & {};
18+
19+
interface D {}
20+
interface E {}
21+
22+
let x10: A & D;
23+
let x11: C & D;
24+
let x12: A & B & C & D;
25+
let x13: D & E;
26+
let x14: A & B & C & D & E;
27+
28+
29+
//// [intersectionsAndEmptyObjects.js]
30+
// Empty object type literals are removed from intersections types
31+
// that contain other object types
32+
var x01;
33+
var x02;
34+
var x03;
35+
var x04;
36+
var x05;
37+
var x06;
38+
var x07;
39+
var x08;
40+
var x09;
41+
var x10;
42+
var x11;
43+
var x12;
44+
var x13;
45+
var x14;
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
=== tests/cases/conformance/types/intersection/intersectionsAndEmptyObjects.ts ===
2+
// Empty object type literals are removed from intersections types
3+
// that contain other object types
4+
5+
type A = { a: number };
6+
>A : Symbol(A, Decl(intersectionsAndEmptyObjects.ts, 0, 0))
7+
>a : Symbol(a, Decl(intersectionsAndEmptyObjects.ts, 3, 10))
8+
9+
type B = { b: string };
10+
>B : Symbol(B, Decl(intersectionsAndEmptyObjects.ts, 3, 23))
11+
>b : Symbol(b, Decl(intersectionsAndEmptyObjects.ts, 4, 10))
12+
13+
type C = {};
14+
>C : Symbol(C, Decl(intersectionsAndEmptyObjects.ts, 4, 23))
15+
16+
let x01: A & B;
17+
>x01 : Symbol(x01, Decl(intersectionsAndEmptyObjects.ts, 7, 3))
18+
>A : Symbol(A, Decl(intersectionsAndEmptyObjects.ts, 0, 0))
19+
>B : Symbol(B, Decl(intersectionsAndEmptyObjects.ts, 3, 23))
20+
21+
let x02: A & C;
22+
>x02 : Symbol(x02, Decl(intersectionsAndEmptyObjects.ts, 8, 3))
23+
>A : Symbol(A, Decl(intersectionsAndEmptyObjects.ts, 0, 0))
24+
>C : Symbol(C, Decl(intersectionsAndEmptyObjects.ts, 4, 23))
25+
26+
let x03: B & C;
27+
>x03 : Symbol(x03, Decl(intersectionsAndEmptyObjects.ts, 9, 3))
28+
>B : Symbol(B, Decl(intersectionsAndEmptyObjects.ts, 3, 23))
29+
>C : Symbol(C, Decl(intersectionsAndEmptyObjects.ts, 4, 23))
30+
31+
let x04: A & B & C;
32+
>x04 : Symbol(x04, Decl(intersectionsAndEmptyObjects.ts, 10, 3))
33+
>A : Symbol(A, Decl(intersectionsAndEmptyObjects.ts, 0, 0))
34+
>B : Symbol(B, Decl(intersectionsAndEmptyObjects.ts, 3, 23))
35+
>C : Symbol(C, Decl(intersectionsAndEmptyObjects.ts, 4, 23))
36+
37+
let x05: string & C;
38+
>x05 : Symbol(x05, Decl(intersectionsAndEmptyObjects.ts, 11, 3))
39+
>C : Symbol(C, Decl(intersectionsAndEmptyObjects.ts, 4, 23))
40+
41+
let x06: C & string;
42+
>x06 : Symbol(x06, Decl(intersectionsAndEmptyObjects.ts, 12, 3))
43+
>C : Symbol(C, Decl(intersectionsAndEmptyObjects.ts, 4, 23))
44+
45+
let x07: C;
46+
>x07 : Symbol(x07, Decl(intersectionsAndEmptyObjects.ts, 13, 3))
47+
>C : Symbol(C, Decl(intersectionsAndEmptyObjects.ts, 4, 23))
48+
49+
let x08: C & {};
50+
>x08 : Symbol(x08, Decl(intersectionsAndEmptyObjects.ts, 14, 3))
51+
>C : Symbol(C, Decl(intersectionsAndEmptyObjects.ts, 4, 23))
52+
53+
let x09: {} & A & {} & B & {} & C & {};
54+
>x09 : Symbol(x09, Decl(intersectionsAndEmptyObjects.ts, 15, 3))
55+
>A : Symbol(A, Decl(intersectionsAndEmptyObjects.ts, 0, 0))
56+
>B : Symbol(B, Decl(intersectionsAndEmptyObjects.ts, 3, 23))
57+
>C : Symbol(C, Decl(intersectionsAndEmptyObjects.ts, 4, 23))
58+
59+
interface D {}
60+
>D : Symbol(D, Decl(intersectionsAndEmptyObjects.ts, 15, 39))
61+
62+
interface E {}
63+
>E : Symbol(E, Decl(intersectionsAndEmptyObjects.ts, 17, 14))
64+
65+
let x10: A & D;
66+
>x10 : Symbol(x10, Decl(intersectionsAndEmptyObjects.ts, 20, 3))
67+
>A : Symbol(A, Decl(intersectionsAndEmptyObjects.ts, 0, 0))
68+
>D : Symbol(D, Decl(intersectionsAndEmptyObjects.ts, 15, 39))
69+
70+
let x11: C & D;
71+
>x11 : Symbol(x11, Decl(intersectionsAndEmptyObjects.ts, 21, 3))
72+
>C : Symbol(C, Decl(intersectionsAndEmptyObjects.ts, 4, 23))
73+
>D : Symbol(D, Decl(intersectionsAndEmptyObjects.ts, 15, 39))
74+
75+
let x12: A & B & C & D;
76+
>x12 : Symbol(x12, Decl(intersectionsAndEmptyObjects.ts, 22, 3))
77+
>A : Symbol(A, Decl(intersectionsAndEmptyObjects.ts, 0, 0))
78+
>B : Symbol(B, Decl(intersectionsAndEmptyObjects.ts, 3, 23))
79+
>C : Symbol(C, Decl(intersectionsAndEmptyObjects.ts, 4, 23))
80+
>D : Symbol(D, Decl(intersectionsAndEmptyObjects.ts, 15, 39))
81+
82+
let x13: D & E;
83+
>x13 : Symbol(x13, Decl(intersectionsAndEmptyObjects.ts, 23, 3))
84+
>D : Symbol(D, Decl(intersectionsAndEmptyObjects.ts, 15, 39))
85+
>E : Symbol(E, Decl(intersectionsAndEmptyObjects.ts, 17, 14))
86+
87+
let x14: A & B & C & D & E;
88+
>x14 : Symbol(x14, Decl(intersectionsAndEmptyObjects.ts, 24, 3))
89+
>A : Symbol(A, Decl(intersectionsAndEmptyObjects.ts, 0, 0))
90+
>B : Symbol(B, Decl(intersectionsAndEmptyObjects.ts, 3, 23))
91+
>C : Symbol(C, Decl(intersectionsAndEmptyObjects.ts, 4, 23))
92+
>D : Symbol(D, Decl(intersectionsAndEmptyObjects.ts, 15, 39))
93+
>E : Symbol(E, Decl(intersectionsAndEmptyObjects.ts, 17, 14))
94+

0 commit comments

Comments
 (0)