Skip to content

Commit 90685ef

Browse files
committed
Extend isEmptyAnonymousObjectType with support for non-generic mapped types
1 parent 01a51d2 commit 90685ef

15 files changed

+18694
-89
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20849,6 +20849,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2084920849
}
2085020850

2085120851
function isEmptyAnonymousObjectType(type: Type) {
20852+
if (getObjectFlags(type) & ObjectFlags.Mapped && !isGenericMappedType(type)) {
20853+
return isEmptyResolvedType(resolveStructuredTypeMembers(type as ObjectType));
20854+
}
2085220855
return !!(getObjectFlags(type) & ObjectFlags.Anonymous && (
2085320856
(type as ResolvedType).members && isEmptyResolvedType(type as ResolvedType) ||
2085420857
type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral && getMembersOfSymbol(type.symbol).size === 0

tests/baselines/reference/declarationEmitPrivatePromiseLikeInterface.errors.txt

Lines changed: 0 additions & 42 deletions
This file was deleted.

tests/baselines/reference/declarationEmitPrivatePromiseLikeInterface.js

Lines changed: 18432 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//// [tests/cases/compiler/emptyObjectMappedTypeWithNeverKey.ts] ////
2+
3+
=== emptyObjectMappedTypeWithNeverKey.ts ===
4+
declare const u: unknown;
5+
>u : Symbol(u, Decl(emptyObjectMappedTypeWithNeverKey.ts, 0, 13))
6+
7+
type A = { [K in never]: any };
8+
>A : Symbol(A, Decl(emptyObjectMappedTypeWithNeverKey.ts, 0, 25))
9+
>K : Symbol(K, Decl(emptyObjectMappedTypeWithNeverKey.ts, 2, 12))
10+
11+
const a: null | undefined | A = u;
12+
>a : Symbol(a, Decl(emptyObjectMappedTypeWithNeverKey.ts, 3, 5))
13+
>A : Symbol(A, Decl(emptyObjectMappedTypeWithNeverKey.ts, 0, 25))
14+
>u : Symbol(u, Decl(emptyObjectMappedTypeWithNeverKey.ts, 0, 13))
15+
16+
type Point = { x: number; y: number };
17+
>Point : Symbol(Point, Decl(emptyObjectMappedTypeWithNeverKey.ts, 3, 34))
18+
>x : Symbol(x, Decl(emptyObjectMappedTypeWithNeverKey.ts, 5, 14))
19+
>y : Symbol(y, Decl(emptyObjectMappedTypeWithNeverKey.ts, 5, 25))
20+
21+
declare function foo<T, K extends keyof T>(
22+
>foo : Symbol(foo, Decl(emptyObjectMappedTypeWithNeverKey.ts, 5, 38))
23+
>T : Symbol(T, Decl(emptyObjectMappedTypeWithNeverKey.ts, 6, 21))
24+
>K : Symbol(K, Decl(emptyObjectMappedTypeWithNeverKey.ts, 6, 23))
25+
>T : Symbol(T, Decl(emptyObjectMappedTypeWithNeverKey.ts, 6, 21))
26+
27+
obj: T,
28+
>obj : Symbol(obj, Decl(emptyObjectMappedTypeWithNeverKey.ts, 6, 43))
29+
>T : Symbol(T, Decl(emptyObjectMappedTypeWithNeverKey.ts, 6, 21))
30+
31+
keys: K[],
32+
>keys : Symbol(keys, Decl(emptyObjectMappedTypeWithNeverKey.ts, 7, 9))
33+
>K : Symbol(K, Decl(emptyObjectMappedTypeWithNeverKey.ts, 6, 23))
34+
35+
rest: Omit<T, K> | null | undefined,
36+
>rest : Symbol(rest, Decl(emptyObjectMappedTypeWithNeverKey.ts, 8, 12))
37+
>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --))
38+
>T : Symbol(T, Decl(emptyObjectMappedTypeWithNeverKey.ts, 6, 21))
39+
>K : Symbol(K, Decl(emptyObjectMappedTypeWithNeverKey.ts, 6, 23))
40+
41+
): void;
42+
const p: Point = { x: 0, y: 0 };
43+
>p : Symbol(p, Decl(emptyObjectMappedTypeWithNeverKey.ts, 11, 5))
44+
>Point : Symbol(Point, Decl(emptyObjectMappedTypeWithNeverKey.ts, 3, 34))
45+
>x : Symbol(x, Decl(emptyObjectMappedTypeWithNeverKey.ts, 11, 18))
46+
>y : Symbol(y, Decl(emptyObjectMappedTypeWithNeverKey.ts, 11, 24))
47+
48+
foo(p, ["x", "y"], u);
49+
>foo : Symbol(foo, Decl(emptyObjectMappedTypeWithNeverKey.ts, 5, 38))
50+
>p : Symbol(p, Decl(emptyObjectMappedTypeWithNeverKey.ts, 11, 5))
51+
>u : Symbol(u, Decl(emptyObjectMappedTypeWithNeverKey.ts, 0, 13))
52+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//// [tests/cases/compiler/emptyObjectMappedTypeWithNeverKey.ts] ////
2+
3+
=== emptyObjectMappedTypeWithNeverKey.ts ===
4+
declare const u: unknown;
5+
>u : unknown
6+
7+
type A = { [K in never]: any };
8+
>A : {}
9+
10+
const a: null | undefined | A = u;
11+
>a : A | null | undefined
12+
>u : unknown
13+
14+
type Point = { x: number; y: number };
15+
>Point : { x: number; y: number; }
16+
>x : number
17+
>y : number
18+
19+
declare function foo<T, K extends keyof T>(
20+
>foo : <T, K extends keyof T>(obj: T, keys: K[], rest: Omit<T, K> | null | undefined) => void
21+
22+
obj: T,
23+
>obj : T
24+
25+
keys: K[],
26+
>keys : K[]
27+
28+
rest: Omit<T, K> | null | undefined,
29+
>rest : Omit<T, K> | null | undefined
30+
31+
): void;
32+
const p: Point = { x: 0, y: 0 };
33+
>p : Point
34+
>{ x: 0, y: 0 } : { x: number; y: number; }
35+
>x : number
36+
>0 : 0
37+
>y : number
38+
>0 : 0
39+
40+
foo(p, ["x", "y"], u);
41+
>foo(p, ["x", "y"], u) : void
42+
>foo : <T, K extends keyof T>(obj: T, keys: K[], rest: Omit<T, K> | null | undefined) => void
43+
>p : Point
44+
>["x", "y"] : ("x" | "y")[]
45+
>"x" : "x"
46+
>"y" : "y"
47+
>u : unknown
48+

tests/baselines/reference/generatorYieldContextualType.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ function canPickStepContinue<T extends QuickPickStep>(
198198
>_step : T
199199

200200
_state: PartialStepState,
201-
>_state : PartialStepState<unknown>
201+
>_state : { counter: number; confirm?: boolean | undefined; startingStep?: number | undefined; }
202202

203203
_selection: StepItemType<T> | Directive
204204
>_selection : Directive | StepItemType<T>
@@ -220,7 +220,7 @@ function createPickStep<T extends QuickPickItem>(
220220
}
221221

222222
function* showStep<
223-
>showStep : <State extends Partial<unknown> & { counter: number; confirm?: boolean | undefined; startingStep?: number | undefined; } & { repo: any; }, Context extends { repos: any[]; title: string; status: any; }>(state: State, _context: Context) => StepResultGenerator<QuickPickItem>
223+
>showStep : <State extends { counter: number; confirm?: boolean | undefined; startingStep?: number | undefined; } & { repo: any; }, Context extends { repos: any[]; title: string; status: any; }>(state: State, _context: Context) => StepResultGenerator<QuickPickItem>
224224

225225
State extends PartialStepState & { repo: any },
226226
>repo : any
@@ -258,7 +258,7 @@ function* showStep<
258258
return canPickStepContinue(step, state, selection)
259259
>canPickStepContinue(step, state, selection) ? selection[0] : StepResult.Break : QuickPickItem | unique symbol
260260
>canPickStepContinue(step, state, selection) : boolean
261-
>canPickStepContinue : <T extends QuickPickStep<QuickPickItem>>(_step: T, _state: PartialStepState<unknown>, _selection: Directive | StepItemType<T>) => _selection is StepItemType<T>
261+
>canPickStepContinue : <T extends QuickPickStep<QuickPickItem>>(_step: T, _state: { counter: number; confirm?: boolean | undefined; startingStep?: number | undefined; }, _selection: Directive | StepItemType<T>) => _selection is StepItemType<T>
262262
>step : QuickPickStep<QuickPickItem>
263263
>state : State
264264
>selection : Directive | QuickPickItem[]

tests/baselines/reference/intersectionWithIndexSignatures.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ intersectionWithIndexSignatures.ts(17,1): error TS2322: Type '{ x: A; } & { y: B
22
Property 'y' is incompatible with index signature.
33
Property 'a' is missing in type 'B' but required in type 'A'.
44
intersectionWithIndexSignatures.ts(27,10): error TS2339: Property 'b' does not exist on type '{ a: string; }'.
5-
intersectionWithIndexSignatures.ts(29,7): error TS2322: Type 's' is not assignable to type '{ [key: string]: { a: string; b: string; }; }'.
5+
intersectionWithIndexSignatures.ts(29,7): error TS2322: Type 'Pick<{ [key: string]: { a: string; }; }, string | number>' is not assignable to type '{ [key: string]: { a: string; b: string; }; }'.
66
'string' index signatures are incompatible.
77
Property 'b' is missing in type '{ a: string; }' but required in type '{ a: string; b: string; }'.
88
intersectionWithIndexSignatures.ts(35,1): error TS2322: Type '{ a: string; } & { b: number; }' is not assignable to type '{ [key: string]: string; }'.
@@ -48,7 +48,7 @@ intersectionWithIndexSignatures.ts(35,1): error TS2322: Type '{ a: string; } & {
4848

4949
const d: { [key: string]: {a: string, b: string} } = q; // Error
5050
~
51-
!!! error TS2322: Type 's' is not assignable to type '{ [key: string]: { a: string; b: string; }; }'.
51+
!!! error TS2322: Type 'Pick<{ [key: string]: { a: string; }; }, string | number>' is not assignable to type '{ [key: string]: { a: string; b: string; }; }'.
5252
!!! error TS2322: 'string' index signatures are incompatible.
5353
!!! error TS2322: Property 'b' is missing in type '{ a: string; }' but required in type '{ a: string; b: string; }'.
5454
!!! related TS2728 intersectionWithIndexSignatures.ts:29:39: 'b' is declared here.

tests/baselines/reference/intersectionWithIndexSignatures.types

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,19 +67,19 @@ type constr<Source, Tgt> = { [K in keyof Source]: string } & Pick<Tgt, Exclude<k
6767
>constr : constr<Source, Tgt>
6868

6969
type s = constr<{}, { [key: string]: { a: string } }>;
70-
>s : {} & Pick<{ [key: string]: { a: string; }; }, string | number>
70+
>s : Pick<{ [key: string]: { a: string; }; }, string | number>
7171
>key : string
7272
>a : string
7373

7474
declare const q: s;
75-
>q : s
75+
>q : Pick<{ [key: string]: { a: string; }; }, string | number>
7676

7777
q["asd"].a.substr(1);
7878
>q["asd"].a.substr(1) : string
7979
>q["asd"].a.substr : (from: number, length?: number | undefined) => string
8080
>q["asd"].a : string
8181
>q["asd"] : { a: string; }
82-
>q : s
82+
>q : Pick<{ [key: string]: { a: string; }; }, string | number>
8383
>"asd" : "asd"
8484
>a : string
8585
>substr : (from: number, length?: number | undefined) => string
@@ -88,7 +88,7 @@ q["asd"].a.substr(1);
8888
q["asd"].b; // Error
8989
>q["asd"].b : any
9090
>q["asd"] : { a: string; }
91-
>q : s
91+
>q : Pick<{ [key: string]: { a: string; }; }, string | number>
9292
>"asd" : "asd"
9393
>b : any
9494

@@ -97,7 +97,7 @@ const d: { [key: string]: {a: string, b: string} } = q; // Error
9797
>key : string
9898
>a : string
9999
>b : string
100-
>q : s
100+
>q : Pick<{ [key: string]: { a: string; }; }, string | number>
101101

102102
// Repro from #32484
103103

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
intersectionsAndEmptyObjects.ts(81,6): error TS2456: Type alias 'Foo2' circularly references itself.
2+
3+
4+
==== intersectionsAndEmptyObjects.ts (1 errors) ====
5+
// Empty object type literals are removed from intersections types
6+
// that contain other object types
7+
8+
type A = { a: number };
9+
type B = { b: string };
10+
type C = {};
11+
12+
let x01: A & B;
13+
let x02: A & C;
14+
let x03: B & C;
15+
let x04: A & B & C;
16+
let x05: string & C;
17+
let x06: C & string;
18+
let x07: C;
19+
let x08: C & {};
20+
let x09: {} & A & {} & B & {} & C & {};
21+
22+
interface D {}
23+
interface E {}
24+
25+
let x10: A & D;
26+
let x11: C & D;
27+
let x12: A & B & C & D;
28+
let x13: D & E;
29+
let x14: A & B & C & D & E;
30+
31+
// Repro from #20225
32+
33+
type Dictionary = { [name: string]: string };
34+
35+
const intersectDictionaries = <F1 extends Dictionary, F2 extends Dictionary>(
36+
d1: F1,
37+
d2: F2,
38+
): F1 & F2 => Object.assign({}, d1, d2);
39+
40+
const testDictionary = <T extends Dictionary>(_value: T) => { };
41+
42+
const d1 = {};
43+
testDictionary(d1);
44+
const d2 = intersectDictionaries(d1, d1);
45+
testDictionary(d2);
46+
47+
const d3 = {
48+
s: '',
49+
};
50+
testDictionary(d3);
51+
const d4 = intersectDictionaries(d1, d3);
52+
testDictionary(d4);
53+
const d5 = intersectDictionaries(d3, d1);
54+
testDictionary(d5);
55+
const d6 = intersectDictionaries(d3, d3);
56+
testDictionary(d6);
57+
58+
// Repro from #27044
59+
60+
type choices<IChoiceList extends {
61+
[key: string]: boolean;
62+
}> = IChoiceList & {
63+
shoes:boolean;
64+
food:boolean;
65+
};
66+
67+
type IMyChoiceList = {
68+
car: true
69+
};
70+
71+
type IUnknownChoiceList = {};
72+
73+
var defaultChoices: choices<{}>;
74+
var defaultChoicesAndEmpty: choices<{} & {}>;
75+
76+
var myChoices: choices<IMyChoiceList>;
77+
var myChoicesAndEmpty: choices<IMyChoiceList & {}>;
78+
79+
var unknownChoices: choices<IUnknownChoiceList>;
80+
var unknownChoicesAndEmpty: choices<IUnknownChoiceList & {}>;
81+
82+
// Repro from #38672
83+
84+
type Foo1 = { x: string } & { [x: number]: Foo1 };
85+
type Foo2 = { x: string } & { [K in number]: Foo2 };
86+
~~~~
87+
!!! error TS2456: Type alias 'Foo2' circularly references itself.
88+
89+
// Repro from #40239
90+
91+
declare function mock<M>(_: Promise<M>): {} & M;
92+
mock(import('./ex'))
93+
94+
==== ex.d.ts (0 errors) ====
95+
export {}
96+

tests/baselines/reference/intersectionsAndEmptyObjects.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ type Foo1 = { x: string } & { [x: number]: Foo1 };
216216
>x : number
217217

218218
type Foo2 = { x: string } & { [K in number]: Foo2 };
219-
>Foo2 : { x: string; } & { [x: number]: Foo2; }
219+
>Foo2 : any
220220
>x : string
221221

222222
// Repro from #40239

0 commit comments

Comments
 (0)