@@ -1813,6 +1813,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
18131813 const unresolvedSymbols = new Map<string, TransientSymbol>();
18141814 const errorTypes = new Map<string, Type>();
18151815
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+
18161820 const anyType = createIntrinsicType(TypeFlags.Any, "any");
18171821 const autoType = createIntrinsicType(TypeFlags.Any, "any", ObjectFlags.NonInferrableType);
18181822 const wildcardType = createIntrinsicType(TypeFlags.Any, "any");
@@ -1824,8 +1828,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
18241828 const nonNullUnknownType = createIntrinsicType(TypeFlags.Unknown, "unknown");
18251829 const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined");
18261830 const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined, "undefined", ObjectFlags.ContainsWideningType);
1831+ const missingType = createIntrinsicType(TypeFlags.Undefined, "undefined");
1832+ const undefinedOrMissingType = exactOptionalPropertyTypes ? missingType : undefinedType;
18271833 const optionalType = createIntrinsicType(TypeFlags.Undefined, "undefined");
1828- const missingType = exactOptionalPropertyTypes ? createIntrinsicType(TypeFlags.Undefined, "undefined") : undefinedType;
18291834 const nullType = createIntrinsicType(TypeFlags.Null, "null");
18301835 const nullWideningType = strictNullChecks ? nullType : createIntrinsicType(TypeFlags.Null, "null", ObjectFlags.ContainsWideningType);
18311836 const stringType = createIntrinsicType(TypeFlags.String, "string");
@@ -15952,10 +15957,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1595215957 includes & TypeFlags.IncludesWildcard ? wildcardType : anyType :
1595315958 includes & TypeFlags.Null || containsType(typeSet, unknownType) ? unknownType : nonNullUnknownType;
1595415959 }
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 );
1595915964 }
1596015965 }
1596115966 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 {
1609616101 if (type === wildcardType) includes |= TypeFlags.IncludesWildcard;
1609716102 }
1609816103 else if (strictNullChecks || !(flags & TypeFlags.Nullable)) {
16099- if (exactOptionalPropertyTypes && type === missingType) {
16104+ if (type === missingType) {
1610016105 includes |= TypeFlags.IncludesMissingType;
1610116106 type = undefinedType;
1610216107 }
@@ -16320,9 +16325,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1632016325 result = getIntersectionType(typeSet, aliasSymbol, aliasTypeArguments);
1632116326 }
1632216327 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;
1632416329 removeFromEach(typeSet, TypeFlags.Undefined);
16325- result = getUnionType([getIntersectionType(typeSet), undefinedOrMissingType ], UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
16330+ result = getUnionType([getIntersectionType(typeSet), containedUndefinedType ], UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
1632616331 }
1632716332 else if (eachIsUnionContaining(typeSet, TypeFlags.Null)) {
1632816333 removeFromEach(typeSet, TypeFlags.Null);
@@ -16853,7 +16858,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1685316858 errorIfWritingToReadonlyIndex(getIndexInfoOfType(objectType, numberType));
1685416859 return mapType(objectType, t => {
1685516860 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;
1685716862 });
1685816863 }
1685916864 }
@@ -16875,7 +16880,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1687516880 if (accessNode && indexInfo.keyType === stringType && !isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) {
1687616881 const indexNode = getIndexNodeForAccessExpression(accessNode);
1687716882 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;
1687916884 }
1688016885 errorIfWritingToReadonlyIndex(indexInfo);
1688116886 // When accessing an enum object with its own type,
@@ -16887,7 +16892,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1688716892 (indexType.symbol &&
1688816893 indexType.flags & TypeFlags.EnumLiteral &&
1688916894 getParentOfSymbol(indexType.symbol) === objectType.symbol))) {
16890- return getUnionType([indexInfo.type, undefinedType ]);
16895+ return getUnionType([indexInfo.type, missingType ]);
1689116896 }
1689216897 return indexInfo.type;
1689316898 }
@@ -20421,8 +20426,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2042120426 }
2042220427
2042320428 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
2042620429 if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union &&
2042720430 !((source as UnionType).types[0].flags & TypeFlags.Undefined) && (target as UnionType).types[0].flags & TypeFlags.Undefined) {
2042820431 return extractTypesOfKind(target, ~TypeFlags.Undefined);
@@ -22790,8 +22793,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2279022793
2279122794 function getOptionalType(type: Type, isProperty = false): Type {
2279222795 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]);
2279522798 }
2279622799
2279722800 function getGlobalNonNullableTypeInstantiation(type: Type) {
@@ -22830,7 +22833,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2283022833 }
2283122834
2283222835 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;
2283422837 }
2283522838
2283622839 function removeMissingOrUndefinedType(type: Type): Type {
@@ -22983,7 +22986,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2298322986 if (cached) {
2298422987 return cached;
2298522988 }
22986- const result = createSymbolWithType(prop, missingType );
22989+ const result = createSymbolWithType(prop, undefinedOrMissingType );
2298722990 result.flags |= SymbolFlags.Optional;
2298822991 undefinedProperties.set(prop.escapedName, result);
2298922992 return result;
@@ -24388,7 +24391,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2438824391 }
2438924392
2439024393 function isTypeOrBaseIdenticalTo(s: Type, t: Type) {
24391- return exactOptionalPropertyTypes && t === missingType ? s === t :
24394+ return t === missingType ? s === t :
2439224395 (isTypeIdenticalTo(s, t) || !!(t.flags & TypeFlags.String && s.flags & TypeFlags.StringLiteral || t.flags & TypeFlags.Number && s.flags & TypeFlags.NumberLiteral));
2439324396 }
2439424397
@@ -25072,7 +25075,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2507225075 function includeUndefinedInIndexSignature(type: Type | undefined): Type | undefined {
2507325076 if (!type) return type;
2507425077 return compilerOptions.noUncheckedIndexedAccess ?
25075- getUnionType([type, undefinedType ]) :
25078+ getUnionType([type, missingType ]) :
2507625079 type;
2507725080 }
2507825081
@@ -29096,7 +29099,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2909629099 }
2909729100 else if (exactOptionalPropertyTypes && e.kind === SyntaxKind.OmittedExpression) {
2909829101 hasOmittedExpression = true;
29099- elementTypes.push(missingType );
29102+ elementTypes.push(undefinedOrMissingType );
2910029103 elementFlags.push(ElementFlags.Optional);
2910129104 }
2910229105 else {
@@ -30640,7 +30643,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3064030643 error(node, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(apparentType));
3064130644 }
3064230645
30643- propType = (compilerOptions.noUncheckedIndexedAccess && !isAssignmentTarget(node)) ? getUnionType([indexInfo.type, undefinedType ]) : indexInfo.type;
30646+ propType = (compilerOptions.noUncheckedIndexedAccess && !isAssignmentTarget(node)) ? getUnionType([indexInfo.type, missingType ]) : indexInfo.type;
3064430647 if (compilerOptions.noPropertyAccessFromIndexSignature && isPropertyAccessExpression(node)) {
3064530648 error(right, Diagnostics.Property_0_comes_from_an_index_signature_so_it_must_be_accessed_with_0, unescapeLeadingUnderscores(right.escapedText));
3064630649 }
0 commit comments