@@ -13310,54 +13310,40 @@ namespace ts {
13310
13310
return includes;
13311
13311
}
13312
13312
13313
- function isSetOfLiteralsFromSameEnum(types: readonly Type[]): boolean {
13314
- const first = types[0];
13315
- if (first.flags & TypeFlags.EnumLiteral) {
13316
- const firstEnum = getParentOfSymbol(first.symbol);
13317
- for (let i = 1; i < types.length; i++) {
13318
- const other = types[i];
13319
- if (!(other.flags & TypeFlags.EnumLiteral) || (firstEnum !== getParentOfSymbol(other.symbol))) {
13320
- return false;
13321
- }
13322
- }
13323
- return true;
13324
- }
13325
-
13326
- return false;
13327
- }
13328
-
13329
- function removeSubtypes(types: Type[], primitivesOnly: boolean): boolean {
13313
+ function removeSubtypes(types: Type[], hasObjectTypes: boolean): boolean {
13314
+ // We assume that redundant primitive types have already been removed from the types array and that there
13315
+ // are no any and unknown types in the array. Thus, the only possible supertypes for primitive types are empty
13316
+ // object types, and if none of those are present we can exclude primitive types from the subtype check.
13317
+ const hasEmptyObject = hasObjectTypes && some(types, t => !!(t.flags & TypeFlags.Object) && !isGenericMappedType(t) && isEmptyResolvedType(resolveStructuredTypeMembers(<ObjectType>t)));
13330
13318
const len = types.length;
13331
- if (len === 0 || isSetOfLiteralsFromSameEnum(types)) {
13332
- return true;
13333
- }
13334
13319
let i = len;
13335
13320
let count = 0;
13336
13321
while (i > 0) {
13337
13322
i--;
13338
13323
const source = types[i];
13339
- for (const target of types) {
13340
- if (source !== target) {
13341
- if (count === 100000) {
13342
- // After 100000 subtype checks we estimate the remaining amount of work by assuming the
13343
- // same ratio of checks per element. If the estimated number of remaining type checks is
13344
- // greater than an upper limit we deem the union type too complex to represent. The
13345
- // upper limit is 25M for unions of primitives only, and 1M otherwise. This for example
13346
- // caps union types at 5000 unique literal types and 1000 unique object types.
13347
- const estimatedCount = (count / (len - i)) * len;
13348
- if (estimatedCount > (primitivesOnly ? 25000000 : 1000000)) {
13349
- tracing.instant(tracing.Phase.CheckTypes, "removeSubtypes_DepthLimit", { typeIds: types.map(t => t.id) });
13350
- error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent);
13351
- return false;
13324
+ if (hasEmptyObject || source.flags & TypeFlags.StructuredOrInstantiable) {
13325
+ for (const target of types) {
13326
+ if (source !== target) {
13327
+ if (count === 100000) {
13328
+ // After 100000 subtype checks we estimate the remaining amount of work by assuming the
13329
+ // same ratio of checks per element. If the estimated number of remaining type checks is
13330
+ // greater than 1M we deem the union type too complex to represent. This for example
13331
+ // caps union types at 1000 unique object types.
13332
+ const estimatedCount = (count / (len - i)) * len;
13333
+ if (estimatedCount > 1000000) {
13334
+ tracing.instant(tracing.Phase.CheckTypes, "removeSubtypes_DepthLimit", { typeIds: types.map(t => t.id) });
13335
+ error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent);
13336
+ return false;
13337
+ }
13338
+ }
13339
+ count++;
13340
+ if (isTypeRelatedTo(source, target, strictSubtypeRelation) && (
13341
+ !(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) ||
13342
+ !(getObjectFlags(getTargetType(target)) & ObjectFlags.Class) ||
13343
+ isTypeDerivedFrom(source, target))) {
13344
+ orderedRemoveItemAt(types, i);
13345
+ break;
13352
13346
}
13353
- }
13354
- count++;
13355
- if (isTypeRelatedTo(source, target, strictSubtypeRelation) && (
13356
- !(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) ||
13357
- !(getObjectFlags(getTargetType(target)) & ObjectFlags.Class) ||
13358
- isTypeDerivedFrom(source, target))) {
13359
- orderedRemoveItemAt(types, i);
13360
- break;
13361
13347
}
13362
13348
}
13363
13349
}
@@ -13370,11 +13356,13 @@ namespace ts {
13370
13356
while (i > 0) {
13371
13357
i--;
13372
13358
const t = types[i];
13359
+ const flags = t.flags;
13373
13360
const remove =
13374
- t.flags & TypeFlags.StringLiteral && includes & TypeFlags.String ||
13375
- t.flags & TypeFlags.NumberLiteral && includes & TypeFlags.Number ||
13376
- t.flags & TypeFlags.BigIntLiteral && includes & TypeFlags.BigInt ||
13377
- t.flags & TypeFlags.UniqueESSymbol && includes & TypeFlags.ESSymbol ||
13361
+ flags & TypeFlags.StringLiteral && includes & TypeFlags.String ||
13362
+ flags & TypeFlags.NumberLiteral && includes & TypeFlags.Number ||
13363
+ flags & TypeFlags.BigIntLiteral && includes & TypeFlags.BigInt ||
13364
+ flags & TypeFlags.UniqueESSymbol && includes & TypeFlags.ESSymbol ||
13365
+ flags & TypeFlags.Undefined && includes & TypeFlags.Void ||
13378
13366
isFreshLiteralType(t) && containsType(types, (<LiteralType>t).regularType);
13379
13367
if (remove) {
13380
13368
orderedRemoveItemAt(types, i);
@@ -13440,20 +13428,18 @@ namespace ts {
13440
13428
if (includes & TypeFlags.AnyOrUnknown) {
13441
13429
return includes & TypeFlags.Any ? includes & TypeFlags.IncludesWildcard ? wildcardType : anyType : unknownType;
13442
13430
}
13443
- switch (unionReduction) {
13444
- case UnionReduction.Literal:
13445
- if (includes & (TypeFlags.Literal | TypeFlags.UniqueESSymbol)) {
13446
- removeRedundantLiteralTypes(typeSet, includes);
13447
- }
13448
- if (includes & TypeFlags.StringLiteral && includes & TypeFlags.TemplateLiteral) {
13449
- removeStringLiteralsMatchedByTemplateLiterals(typeSet);
13450
- }
13451
- break;
13452
- case UnionReduction.Subtype:
13453
- if (!removeSubtypes(typeSet, !(includes & TypeFlags.IncludesStructuredOrInstantiable))) {
13454
- return errorType;
13455
- }
13456
- break;
13431
+ if (unionReduction & (UnionReduction.Literal | UnionReduction.Subtype)) {
13432
+ if (includes & (TypeFlags.Literal | TypeFlags.UniqueESSymbol) || includes & TypeFlags.Void && includes & TypeFlags.Undefined) {
13433
+ removeRedundantLiteralTypes(typeSet, includes);
13434
+ }
13435
+ if (includes & TypeFlags.StringLiteral && includes & TypeFlags.TemplateLiteral) {
13436
+ removeStringLiteralsMatchedByTemplateLiterals(typeSet);
13437
+ }
13438
+ }
13439
+ if (unionReduction & UnionReduction.Subtype) {
13440
+ if (!removeSubtypes(typeSet, !!(includes & TypeFlags.Object))) {
13441
+ return errorType;
13442
+ }
13457
13443
}
13458
13444
if (typeSet.length === 0) {
13459
13445
return includes & TypeFlags.Null ? includes & TypeFlags.IncludesNonWideningType ? nullType : nullWideningType :
@@ -28985,7 +28971,7 @@ namespace ts {
28985
28971
if (returnType.flags & TypeFlags.ESSymbolLike && isSymbolOrSymbolForCall(node)) {
28986
28972
return getESSymbolLikeTypeForNode(walkUpParenthesizedExpressions(node.parent));
28987
28973
}
28988
- if (node.kind === SyntaxKind.CallExpression && node.parent.kind === SyntaxKind.ExpressionStatement &&
28974
+ if (node.kind === SyntaxKind.CallExpression && !node.questionDotToken && node.parent.kind === SyntaxKind.ExpressionStatement &&
28989
28975
returnType.flags & TypeFlags.Void && getTypePredicateOfSignature(signature)) {
28990
28976
if (!isDottedName(node.expression)) {
28991
28977
error(node.expression, Diagnostics.Assertions_require_the_call_target_to_be_an_identifier_or_qualified_name);
0 commit comments