Skip to content

Commit e7a4b10

Browse files
committed
Do not materialize optional undefined properties inside actual types
1 parent 52a46c6 commit e7a4b10

13 files changed

+103198
-199
lines changed

src/compiler/checker.ts

Lines changed: 255 additions & 147 deletions
Large diffs are not rendered by default.

src/compiler/types.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3890,7 +3890,9 @@ namespace ts {
38903890
/* @internal */
38913891
EmptyObject = ContainsAnyFunctionType,
38923892
/* @internal */
3893-
ConstructionFlags = NonWideningType | Wildcard | EmptyObject,
3893+
AllFresh = EnumLiteral,
3894+
/* @internal */
3895+
ConstructionFlags = NonWideningType | Wildcard | EmptyObject | AllFresh,
38943896
// The following flag is used for different purposes by maybeTypeOfKind
38953897
/* @internal */
38963898
GenericMappedType = ContainsWideningType
@@ -3988,6 +3990,8 @@ namespace ts {
39883990
/* @internal */ constructSignatures?: ReadonlyArray<Signature>; // Construct signatures of type
39893991
/* @internal */ stringIndexInfo?: IndexInfo; // String indexing info
39903992
/* @internal */ numberIndexInfo?: IndexInfo; // Numeric indexing info
3993+
/* @internal */ regularType?: this;
3994+
/* @internal */ freshType?: this;
39913995
}
39923996

39933997
/** Class and interface types (ObjectFlags.Class and ObjectFlags.Interface). */
@@ -4071,9 +4075,22 @@ namespace ts {
40714075
couldContainTypeVariables: boolean;
40724076
}
40734077

4078+
/* @internal */
4079+
export const enum UnionFlags {
4080+
PrimitiveOnly = 1 << 0,
4081+
FreshObjectsOnly = 1 << 1,
4082+
WidenedFreshObjectsOnly = 1 << 2,
4083+
}
4084+
40744085
export interface UnionType extends UnionOrIntersectionType {
40754086
/* @internal */
4076-
primitiveTypesOnly: boolean;
4087+
unionFlags: UnionFlags;
4088+
/* @internal */
4089+
propertyNameCache?: UnderscoreEscapedMap<true>; // Cache of possible property names
4090+
/* @internal */
4091+
freshType?: this; // Pointer back to the original `FreshObjectsOnly` union for `WidenedFreshObjectsOnly` unions
4092+
/* @internal */
4093+
regularType?: this; // Pointer to the widened union for `FreshObjectsOnly` unions, if it has been made
40774094
}
40784095

40794096
export interface IntersectionType extends UnionOrIntersectionType {
@@ -4122,14 +4139,6 @@ namespace ts {
41224139
constructSignatures: ReadonlyArray<Signature>; // Construct signatures of type
41234140
}
41244141

4125-
/* @internal */
4126-
// Object literals are initially marked fresh. Freshness disappears following an assignment,
4127-
// before a type assertion, or when an object literal's type is widened. The regular
4128-
// version of a fresh type is identical except for the TypeFlags.FreshObjectLiteral flag.
4129-
export interface FreshObjectLiteralType extends ResolvedType {
4130-
regularType: ResolvedType; // Regular version of fresh type
4131-
}
4132-
41334142
// Just a place to cache element types of iterables and iterators
41344143
/* @internal */
41354144
export interface IterableOrIteratorType extends ObjectType, UnionType {

src/compiler/utilities.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ namespace ts {
2020
export const externalHelpersModuleNameText = "tslib";
2121

2222
export const defaultMaximumTruncationLength = 160;
23+
export const defaultHardCapTrunctionLength = 100000; // Trunction limit used even when `noErrorTruncation` is on to avoid OOM when printing huge types
2324

2425
export function getDeclarationOfKind<T extends Declaration>(symbol: Symbol, kind: T["kind"]): T | undefined {
2526
const declarations = symbol.declarations;

src/harness/harness.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1107,7 +1107,8 @@ namespace Harness {
11071107
{ name: "symlink", type: "string" },
11081108
{ name: "link", type: "string" },
11091109
// Emitted js baseline will print full paths for every output file
1110-
{ name: "fullEmitPaths", type: "boolean" }
1110+
{ name: "fullEmitPaths", type: "boolean" },
1111+
{ name: "skipTypeAndSymbol", type: "boolean" }
11111112
];
11121113

11131114
let optionsIndex: ts.Map<ts.CommandLineOption>;

src/testRunner/compilerRunner.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ class CompilerTest {
246246
}
247247

248248
public verifyTypesAndSymbols() {
249+
if (this.harnessSettings.skipTypeAndSymbol) {
250+
return;
251+
}
249252
if (this.fileName.indexOf("APISample") >= 0) {
250253
return;
251254
}

tests/baselines/reference/complexArrayLiteral.js

Lines changed: 68593 additions & 0 deletions
Large diffs are not rendered by default.

tests/baselines/reference/conditionalTypeDoesntSpinForever.types

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -449,22 +449,22 @@ export enum PubSubRecordIsStoredInRedisAsA {
449449
>{} : {}
450450

451451
buildNameFieldConstructor(soFar),
452-
>buildNameFieldConstructor(soFar) : { name?: undefined; } | { name: <TYPE>(instance?: TYPE) => BuildPubSubRecordType<SO_FAR & { name: TYPE; }>; }
452+
>buildNameFieldConstructor(soFar) : {} | { name: <TYPE>(instance?: TYPE) => BuildPubSubRecordType<SO_FAR & { name: TYPE; }>; }
453453
>buildNameFieldConstructor : <SO_FAR>(soFar: SO_FAR) => { name?: undefined; } | { name: <TYPE>(instance?: TYPE) => BuildPubSubRecordType<SO_FAR & { name: TYPE; }>; }
454454
>soFar : SO_FAR
455455

456456
buildIdentifierFieldConstructor(soFar),
457-
>buildIdentifierFieldConstructor(soFar) : { identifier?: undefined; } | { identifier: <TYPE>(instance?: TYPE) => BuildPubSubRecordType<SO_FAR & { identifier: TYPE; }>; }
457+
>buildIdentifierFieldConstructor(soFar) : {} | { identifier: <TYPE>(instance?: TYPE) => BuildPubSubRecordType<SO_FAR & { identifier: TYPE; }>; }
458458
>buildIdentifierFieldConstructor : <SO_FAR>(soFar: SO_FAR) => { identifier?: undefined; } | { identifier: <TYPE>(instance?: TYPE) => BuildPubSubRecordType<SO_FAR & { identifier: TYPE; }>; }
459459
>soFar : SO_FAR
460460

461461
buildRecordFieldConstructor(soFar),
462-
>buildRecordFieldConstructor(soFar) : { record?: undefined; } | { record: <TYPE>(instance?: TYPE) => BuildPubSubRecordType<SO_FAR & { record: TYPE; }>; }
462+
>buildRecordFieldConstructor(soFar) : {} | { record: <TYPE>(instance?: TYPE) => BuildPubSubRecordType<SO_FAR & { record: TYPE; }>; }
463463
>buildRecordFieldConstructor : <SO_FAR>(soFar: SO_FAR) => { record?: undefined; } | { record: <TYPE>(instance?: TYPE) => BuildPubSubRecordType<SO_FAR & { record: TYPE; }>; }
464464
>soFar : SO_FAR
465465

466466
buildStoredAsConstructor(soFar),
467-
>buildStoredAsConstructor(soFar) : { storedAsJsonEncodedRedisString?: undefined; storedAsRedisHash?: undefined; } | { storedAsJsonEncodedRedisString: () => BuildPubSubRecordType<SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString; }>; storedAsRedisHash: () => BuildPubSubRecordType<SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA.redisHash; }>; }
467+
>buildStoredAsConstructor(soFar) : {} | { storedAsJsonEncodedRedisString: () => BuildPubSubRecordType<SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString; }>; storedAsRedisHash: () => BuildPubSubRecordType<SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA.redisHash; }>; }
468468
>buildStoredAsConstructor : <SO_FAR>(soFar: SO_FAR) => { storedAsJsonEncodedRedisString?: undefined; storedAsRedisHash?: undefined; } | { storedAsJsonEncodedRedisString: () => BuildPubSubRecordType<SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString; }>; storedAsRedisHash: () => BuildPubSubRecordType<SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA.redisHash; }>; }
469469
>soFar : SO_FAR
470470

@@ -474,7 +474,7 @@ export enum PubSubRecordIsStoredInRedisAsA {
474474
>soFar : SO_FAR
475475

476476
buildType(soFar)
477-
>buildType(soFar) : { type?: undefined; fields?: undefined; hasField?: undefined; } | { type: SO_FAR; fields: () => Set<keyof SO_FAR>; hasField: (fieldName: string | number | symbol) => boolean; }
477+
>buildType(soFar) : {} | { type: SO_FAR; fields: () => Set<keyof SO_FAR>; hasField: (fieldName: string | number | symbol) => boolean; }
478478
>buildType : <SO_FAR>(soFar: SO_FAR) => { type?: undefined; fields?: undefined; hasField?: undefined; } | { type: SO_FAR; fields: () => Set<keyof SO_FAR>; hasField: (fieldName: string | number | symbol) => boolean; }
479479
>soFar : SO_FAR
480480

tests/baselines/reference/objectLiteralFreshnessWithSpread.errors.txt

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

tests/baselines/reference/objectLiteralNormalization.errors.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts
44
tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts(9,1): error TS2322: Type '{ c: true; }' is not assignable to type '{ a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'.
55
Type '{ c: true; }' is missing the following properties from type '{ a: number; b: string; c: boolean; }': a, b
66
tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts(17,1): error TS2322: Type '{ a: string; b: number; }' is not assignable to type '{ a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; }'.
7-
Type '{ a: string; b: number; }' is not assignable to type '{ a?: undefined; b?: undefined; }'.
7+
Type '{ a: string; b: number; }' is not assignable to type '{ a: number; b: number; }'.
88
Types of property 'a' are incompatible.
9-
Type 'string' is not assignable to type 'undefined'.
9+
Type 'string' is not assignable to type 'number'.
1010
tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts(18,1): error TS2322: Type '{ a: number; }' is not assignable to type '{ a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; }'.
1111
Property 'b' is missing in type '{ a: number; }' but required in type '{ a: number; b: number; }'.
1212

@@ -21,7 +21,7 @@ tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts
2121
a1 = { a: 0, b: 0 }; // Error
2222
~
2323
!!! error TS2322: Type 'number' is not assignable to type 'string | undefined'.
24-
!!! related TS6500 tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts:2:47: The expected type comes from property 'b' which is declared here on type '{ a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'
24+
!!! related TS6500 tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts:2:29: The expected type comes from property 'b' which is declared here on type '{ a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'
2525
a1 = { b: "y" }; // Error
2626
~~
2727
!!! error TS2322: Type '{ b: string; }' is not assignable to type '{ a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'.
@@ -40,9 +40,9 @@ tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts
4040
a2 = { a: "def", b: 20 }; // Error
4141
~~
4242
!!! error TS2322: Type '{ a: string; b: number; }' is not assignable to type '{ a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; }'.
43-
!!! error TS2322: Type '{ a: string; b: number; }' is not assignable to type '{ a?: undefined; b?: undefined; }'.
43+
!!! error TS2322: Type '{ a: string; b: number; }' is not assignable to type '{ a: number; b: number; }'.
4444
!!! error TS2322: Types of property 'a' are incompatible.
45-
!!! error TS2322: Type 'string' is not assignable to type 'undefined'.
45+
!!! error TS2322: Type 'string' is not assignable to type 'number'.
4646
a2 = { a: 1 }; // Error
4747
~~
4848
!!! error TS2322: Type '{ a: number; }' is not assignable to type '{ a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; }'.

tests/baselines/reference/objectLiteralNormalization.symbols

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ a1.a; // number
1515
>a : Symbol(a, Decl(objectLiteralNormalization.ts, 1, 11), Decl(objectLiteralNormalization.ts, 1, 21), Decl(objectLiteralNormalization.ts, 1, 39))
1616

1717
a1.b; // string | undefined
18-
>a1.b : Symbol(b, Decl(objectLiteralNormalization.ts, 1, 45), Decl(objectLiteralNormalization.ts, 1, 27), Decl(objectLiteralNormalization.ts, 1, 45))
18+
>a1.b : Symbol(b, Decl(objectLiteralNormalization.ts, 1, 27), Decl(objectLiteralNormalization.ts, 1, 45))
1919
>a1 : Symbol(a1, Decl(objectLiteralNormalization.ts, 1, 3))
20-
>b : Symbol(b, Decl(objectLiteralNormalization.ts, 1, 45), Decl(objectLiteralNormalization.ts, 1, 27), Decl(objectLiteralNormalization.ts, 1, 45))
20+
>b : Symbol(b, Decl(objectLiteralNormalization.ts, 1, 27), Decl(objectLiteralNormalization.ts, 1, 45))
2121

2222
a1.c; // boolean | undefined
23-
>a1.c : Symbol(c, Decl(objectLiteralNormalization.ts, 1, 53), Decl(objectLiteralNormalization.ts, 1, 53))
23+
>a1.c : Symbol(c, Decl(objectLiteralNormalization.ts, 1, 53))
2424
>a1 : Symbol(a1, Decl(objectLiteralNormalization.ts, 1, 3))
25-
>c : Symbol(c, Decl(objectLiteralNormalization.ts, 1, 53), Decl(objectLiteralNormalization.ts, 1, 53))
25+
>c : Symbol(c, Decl(objectLiteralNormalization.ts, 1, 53))
2626

2727
a1 = { a: 1 };
2828
>a1 : Symbol(a1, Decl(objectLiteralNormalization.ts, 1, 3))
@@ -48,14 +48,14 @@ let a2 = [{ a: 1, b: 2 }, { a: "abc" }, {}][0];
4848
>a : Symbol(a, Decl(objectLiteralNormalization.ts, 10, 27))
4949

5050
a2.a; // string | number | undefined
51-
>a2.a : Symbol(a, Decl(objectLiteralNormalization.ts, 10, 11), Decl(objectLiteralNormalization.ts, 10, 27), Decl(objectLiteralNormalization.ts, 10, 27))
51+
>a2.a : Symbol(a, Decl(objectLiteralNormalization.ts, 10, 11), Decl(objectLiteralNormalization.ts, 10, 27))
5252
>a2 : Symbol(a2, Decl(objectLiteralNormalization.ts, 10, 3))
53-
>a : Symbol(a, Decl(objectLiteralNormalization.ts, 10, 11), Decl(objectLiteralNormalization.ts, 10, 27), Decl(objectLiteralNormalization.ts, 10, 27))
53+
>a : Symbol(a, Decl(objectLiteralNormalization.ts, 10, 11), Decl(objectLiteralNormalization.ts, 10, 27))
5454

5555
a2.b; // number | undefined
56-
>a2.b : Symbol(b, Decl(objectLiteralNormalization.ts, 10, 17), Decl(objectLiteralNormalization.ts, 1, 45))
56+
>a2.b : Symbol(b, Decl(objectLiteralNormalization.ts, 10, 17))
5757
>a2 : Symbol(a2, Decl(objectLiteralNormalization.ts, 10, 3))
58-
>b : Symbol(b, Decl(objectLiteralNormalization.ts, 10, 17), Decl(objectLiteralNormalization.ts, 1, 45))
58+
>b : Symbol(b, Decl(objectLiteralNormalization.ts, 10, 17))
5959

6060
a2 = { a: 10, b: 20 };
6161
>a2 : Symbol(a2, Decl(objectLiteralNormalization.ts, 10, 3))
@@ -144,32 +144,32 @@ d1.pos;
144144
>pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58))
145145

146146
d1.pos.x;
147-
>d1.pos.x : Symbol(x, Decl(objectLiteralNormalization.ts, 33, 29), Decl(objectLiteralNormalization.ts, 33, 29))
147+
>d1.pos.x : Symbol(x, Decl(objectLiteralNormalization.ts, 33, 29))
148148
>d1.pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58))
149149
>d1 : Symbol(d1, Decl(objectLiteralNormalization.ts, 33, 3))
150150
>pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58))
151-
>x : Symbol(x, Decl(objectLiteralNormalization.ts, 33, 29), Decl(objectLiteralNormalization.ts, 33, 29))
151+
>x : Symbol(x, Decl(objectLiteralNormalization.ts, 33, 29))
152152

153153
d1.pos.y;
154-
>d1.pos.y : Symbol(y, Decl(objectLiteralNormalization.ts, 33, 35), Decl(objectLiteralNormalization.ts, 33, 35))
154+
>d1.pos.y : Symbol(y, Decl(objectLiteralNormalization.ts, 33, 35))
155155
>d1.pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58))
156156
>d1 : Symbol(d1, Decl(objectLiteralNormalization.ts, 33, 3))
157157
>pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58))
158-
>y : Symbol(y, Decl(objectLiteralNormalization.ts, 33, 35), Decl(objectLiteralNormalization.ts, 33, 35))
158+
>y : Symbol(y, Decl(objectLiteralNormalization.ts, 33, 35))
159159

160160
d1.pos.a;
161-
>d1.pos.a : Symbol(a, Decl(objectLiteralNormalization.ts, 10, 27), Decl(objectLiteralNormalization.ts, 33, 73))
161+
>d1.pos.a : Symbol(a, Decl(objectLiteralNormalization.ts, 33, 73))
162162
>d1.pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58))
163163
>d1 : Symbol(d1, Decl(objectLiteralNormalization.ts, 33, 3))
164164
>pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58))
165-
>a : Symbol(a, Decl(objectLiteralNormalization.ts, 10, 27), Decl(objectLiteralNormalization.ts, 33, 73))
165+
>a : Symbol(a, Decl(objectLiteralNormalization.ts, 33, 73))
166166

167167
d1.pos.b;
168-
>d1.pos.b : Symbol(b, Decl(objectLiteralNormalization.ts, 1, 45), Decl(objectLiteralNormalization.ts, 33, 86))
168+
>d1.pos.b : Symbol(b, Decl(objectLiteralNormalization.ts, 33, 86))
169169
>d1.pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58))
170170
>d1 : Symbol(d1, Decl(objectLiteralNormalization.ts, 33, 3))
171171
>pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58))
172-
>b : Symbol(b, Decl(objectLiteralNormalization.ts, 1, 45), Decl(objectLiteralNormalization.ts, 33, 86))
172+
>b : Symbol(b, Decl(objectLiteralNormalization.ts, 33, 86))
173173

174174
declare function f<T>(...items: T[]): T;
175175
>f : Symbol(f, Decl(objectLiteralNormalization.ts, 39, 9))

0 commit comments

Comments
 (0)