@@ -1813,6 +1813,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1813
1813
const unresolvedSymbols = new Map<string, TransientSymbol>();
1814
1814
const errorTypes = new Map<string, Type>();
1815
1815
1816
+ // We specifically create the `undefined` and `null` types before any other types that can occur in
1817
+ // unions such that they are given low type IDs and occur first in the sorted list of union constituents.
1818
+ // We can then just examine the first constituent(s) of a union to check for their presence.
1819
+
1816
1820
const anyType = createIntrinsicType(TypeFlags.Any, "any");
1817
1821
const autoType = createIntrinsicType(TypeFlags.Any, "any", ObjectFlags.NonInferrableType);
1818
1822
const wildcardType = createIntrinsicType(TypeFlags.Any, "any");
@@ -1824,8 +1828,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1824
1828
const nonNullUnknownType = createIntrinsicType(TypeFlags.Unknown, "unknown");
1825
1829
const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined");
1826
1830
const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined, "undefined", ObjectFlags.ContainsWideningType);
1831
+ const missingType = createIntrinsicType(TypeFlags.Undefined, "undefined");
1832
+ const undefinedOrMissingType = exactOptionalPropertyTypes ? missingType : undefinedType;
1827
1833
const optionalType = createIntrinsicType(TypeFlags.Undefined, "undefined");
1828
- const missingType = exactOptionalPropertyTypes ? createIntrinsicType(TypeFlags.Undefined, "undefined") : undefinedType;
1829
1834
const nullType = createIntrinsicType(TypeFlags.Null, "null");
1830
1835
const nullWideningType = strictNullChecks ? nullType : createIntrinsicType(TypeFlags.Null, "null", ObjectFlags.ContainsWideningType);
1831
1836
const stringType = createIntrinsicType(TypeFlags.String, "string");
@@ -15952,10 +15957,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
15952
15957
includes & TypeFlags.IncludesWildcard ? wildcardType : anyType :
15953
15958
includes & TypeFlags.Null || containsType(typeSet, unknownType) ? unknownType : nonNullUnknownType;
15954
15959
}
15955
- if (exactOptionalPropertyTypes && includes & TypeFlags.Undefined) {
15956
- const missingIndex = binarySearch(typeSet, missingType, getTypeId, compareValues);
15957
- if (missingIndex >= 0 && containsType( typeSet, undefinedType) ) {
15958
- orderedRemoveItemAt(typeSet, missingIndex );
15960
+ if (includes & TypeFlags.Undefined) {
15961
+ // If type set contains both undefinedType and missingType, remove missingType
15962
+ if (typeSet.length >= 2 && typeSet[0] === undefinedType && typeSet[1] === missingType ) {
15963
+ orderedRemoveItemAt(typeSet, 1 );
15959
15964
}
15960
15965
}
15961
15966
if (includes & (TypeFlags.Literal | TypeFlags.UniqueESSymbol | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || includes & TypeFlags.Void && includes & TypeFlags.Undefined) {
@@ -16096,7 +16101,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
16096
16101
if (type === wildcardType) includes |= TypeFlags.IncludesWildcard;
16097
16102
}
16098
16103
else if (strictNullChecks || !(flags & TypeFlags.Nullable)) {
16099
- if (exactOptionalPropertyTypes && type === missingType) {
16104
+ if (type === missingType) {
16100
16105
includes |= TypeFlags.IncludesMissingType;
16101
16106
type = undefinedType;
16102
16107
}
@@ -16320,9 +16325,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
16320
16325
result = getIntersectionType(typeSet, aliasSymbol, aliasTypeArguments);
16321
16326
}
16322
16327
else if (eachIsUnionContaining(typeSet, TypeFlags.Undefined)) {
16323
- const undefinedOrMissingType = exactOptionalPropertyTypes && some(typeSet, t => containsType((t as UnionType).types, missingType) ) ? missingType : undefinedType;
16328
+ const containedUndefinedType = some(typeSet, containsMissingType ) ? missingType : undefinedType;
16324
16329
removeFromEach(typeSet, TypeFlags.Undefined);
16325
- result = getUnionType([getIntersectionType(typeSet), undefinedOrMissingType ], UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
16330
+ result = getUnionType([getIntersectionType(typeSet), containedUndefinedType ], UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
16326
16331
}
16327
16332
else if (eachIsUnionContaining(typeSet, TypeFlags.Null)) {
16328
16333
removeFromEach(typeSet, TypeFlags.Null);
@@ -16853,7 +16858,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
16853
16858
errorIfWritingToReadonlyIndex(getIndexInfoOfType(objectType, numberType));
16854
16859
return mapType(objectType, t => {
16855
16860
const restType = getRestTypeOfTupleType(t as TupleTypeReference) || undefinedType;
16856
- return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([restType, undefinedType ]) : restType;
16861
+ return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([restType, missingType ]) : restType;
16857
16862
});
16858
16863
}
16859
16864
}
@@ -16875,7 +16880,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
16875
16880
if (accessNode && indexInfo.keyType === stringType && !isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) {
16876
16881
const indexNode = getIndexNodeForAccessExpression(accessNode);
16877
16882
error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType));
16878
- return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([indexInfo.type, undefinedType ]) : indexInfo.type;
16883
+ return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([indexInfo.type, missingType ]) : indexInfo.type;
16879
16884
}
16880
16885
errorIfWritingToReadonlyIndex(indexInfo);
16881
16886
// When accessing an enum object with its own type,
@@ -16887,7 +16892,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
16887
16892
(indexType.symbol &&
16888
16893
indexType.flags & TypeFlags.EnumLiteral &&
16889
16894
getParentOfSymbol(indexType.symbol) === objectType.symbol))) {
16890
- return getUnionType([indexInfo.type, undefinedType ]);
16895
+ return getUnionType([indexInfo.type, missingType ]);
16891
16896
}
16892
16897
return indexInfo.type;
16893
16898
}
@@ -20421,8 +20426,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
20421
20426
}
20422
20427
20423
20428
function getUndefinedStrippedTargetIfNeeded(source: Type, target: Type) {
20424
- // As a builtin type, `undefined` is a very low type ID - making it almsot always first, making this a very fast check to see
20425
- // if we need to strip `undefined` from the target
20426
20429
if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union &&
20427
20430
!((source as UnionType).types[0].flags & TypeFlags.Undefined) && (target as UnionType).types[0].flags & TypeFlags.Undefined) {
20428
20431
return extractTypesOfKind(target, ~TypeFlags.Undefined);
@@ -22790,8 +22793,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
22790
22793
22791
22794
function getOptionalType(type: Type, isProperty = false): Type {
22792
22795
Debug.assert(strictNullChecks);
22793
- const missingOrUndefined = isProperty ? missingType : undefinedType;
22794
- return type.flags & TypeFlags.Undefined || type.flags & TypeFlags.Union && (type as UnionType).types[0] === missingOrUndefined ? type : getUnionType([type, missingOrUndefined]);
22796
+ const missingOrUndefined = isProperty ? undefinedOrMissingType : undefinedType;
22797
+ return type === missingOrUndefined || type.flags & TypeFlags.Union && (type as UnionType).types[0] === missingOrUndefined ? type : getUnionType([type, missingOrUndefined]);
22795
22798
}
22796
22799
22797
22800
function getGlobalNonNullableTypeInstantiation(type: Type) {
@@ -22830,7 +22833,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
22830
22833
}
22831
22834
22832
22835
function containsMissingType(type: Type) {
22833
- return exactOptionalPropertyTypes && ( type === missingType || type.flags & TypeFlags.Union && containsType(( type as UnionType).types, missingType)) ;
22836
+ return type === missingType || !!( type.flags & TypeFlags.Union) && ( type as UnionType).types[0] === missingType;
22834
22837
}
22835
22838
22836
22839
function removeMissingOrUndefinedType(type: Type): Type {
@@ -22983,7 +22986,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
22983
22986
if (cached) {
22984
22987
return cached;
22985
22988
}
22986
- const result = createSymbolWithType(prop, missingType );
22989
+ const result = createSymbolWithType(prop, undefinedOrMissingType );
22987
22990
result.flags |= SymbolFlags.Optional;
22988
22991
undefinedProperties.set(prop.escapedName, result);
22989
22992
return result;
@@ -24388,7 +24391,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
24388
24391
}
24389
24392
24390
24393
function isTypeOrBaseIdenticalTo(s: Type, t: Type) {
24391
- return exactOptionalPropertyTypes && t === missingType ? s === t :
24394
+ return t === missingType ? s === t :
24392
24395
(isTypeIdenticalTo(s, t) || !!(t.flags & TypeFlags.String && s.flags & TypeFlags.StringLiteral || t.flags & TypeFlags.Number && s.flags & TypeFlags.NumberLiteral));
24393
24396
}
24394
24397
@@ -25072,7 +25075,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
25072
25075
function includeUndefinedInIndexSignature(type: Type | undefined): Type | undefined {
25073
25076
if (!type) return type;
25074
25077
return compilerOptions.noUncheckedIndexedAccess ?
25075
- getUnionType([type, undefinedType ]) :
25078
+ getUnionType([type, missingType ]) :
25076
25079
type;
25077
25080
}
25078
25081
@@ -29096,7 +29099,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
29096
29099
}
29097
29100
else if (exactOptionalPropertyTypes && e.kind === SyntaxKind.OmittedExpression) {
29098
29101
hasOmittedExpression = true;
29099
- elementTypes.push(missingType );
29102
+ elementTypes.push(undefinedOrMissingType );
29100
29103
elementFlags.push(ElementFlags.Optional);
29101
29104
}
29102
29105
else {
@@ -30640,7 +30643,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
30640
30643
error(node, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(apparentType));
30641
30644
}
30642
30645
30643
- propType = (compilerOptions.noUncheckedIndexedAccess && !isAssignmentTarget(node)) ? getUnionType([indexInfo.type, undefinedType ]) : indexInfo.type;
30646
+ propType = (compilerOptions.noUncheckedIndexedAccess && !isAssignmentTarget(node)) ? getUnionType([indexInfo.type, missingType ]) : indexInfo.type;
30644
30647
if (compilerOptions.noPropertyAccessFromIndexSignature && isPropertyAccessExpression(node)) {
30645
30648
error(right, Diagnostics.Property_0_comes_from_an_index_signature_so_it_must_be_accessed_with_0, unescapeLeadingUnderscores(right.escapedText));
30646
30649
}
0 commit comments