diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 617934cbb38be..6328bc3ac400c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -74,7 +74,7 @@ namespace ts { TypeofNEString = 1 << 8, // typeof x !== "string" TypeofNENumber = 1 << 9, // typeof x !== "number" TypeofNEBigInt = 1 << 10, // typeof x !== "bigint" - TypeofNEBoolean = 1 << 11, // typeof x !== "boolean" + TypeofNEBoolean = 1 << 11, // typeof x !== "boolean" TypeofNESymbol = 1 << 12, // typeof x !== "symbol" TypeofNEObject = 1 << 13, // typeof x !== "object" TypeofNEFunction = 1 << 14, // typeof x !== "function" @@ -87,10 +87,7 @@ namespace ts { NEUndefinedOrNull = 1 << 21, // x != undefined / x != null Truthy = 1 << 22, // x Falsy = 1 << 23, // !x - IsUndefined = 1 << 24, // Exactly undefined - IsNull = 1 << 25, // Exactly null - IsUndefinedOrNull = IsUndefined | IsNull, - All = (1 << 27) - 1, + All = (1 << 24) - 1, // The following members encode facts about particular kinds of types for use in the getTypeFacts function. // The presence of a particular fact means that the given test is true for some (and possibly all) values // of that kind of type. @@ -132,13 +129,11 @@ namespace ts { ObjectFacts = ObjectStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, FunctionFacts = FunctionStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, - VoidFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy, - UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy | IsUndefined, - NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy | IsNull, - EmptyObjectStrictFacts = All & ~(EQUndefined | EQNull | EQUndefinedOrNull | IsUndefinedOrNull), - EmptyObjectFacts = All & ~IsUndefinedOrNull, - UnknownFacts = All & ~IsUndefinedOrNull, + UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy, + NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy, + EmptyObjectStrictFacts = All & ~(EQUndefined | EQNull | EQUndefinedOrNull), AllTypeofNE = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | NEUndefined, + EmptyObjectFacts = All, // Masks OrFactsMask = TypeofEQFunction | TypeofNEObject, AndFactsMask = All & ~OrFactsMask, @@ -8910,7 +8905,7 @@ namespace ts { if (getEffectiveTypeAnnotationNode(walkUpBindingElementsAndPatterns(declaration))) { // In strict null checking mode, if a default value of a non-undefined type is specified, remove // undefined from the final type. - return strictNullChecks && !(getTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal)) & TypeFacts.IsUndefined) ? getNonUndefinedType(type) : type; + return strictNullChecks && !(getFalsyFlags(checkDeclarationInitializer(declaration, CheckMode.Normal)) & TypeFlags.Undefined) ? getNonUndefinedType(type) : type; } return widenTypeInferredFromInitializer(declaration, getUnionType([getNonUndefinedType(type), checkDeclarationInitializer(declaration, CheckMode.Normal)], UnionReduction.Subtype)); } @@ -18019,7 +18014,7 @@ namespace ts { const sourceSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(sourceType)); const targetSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(targetType)); const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) && - (getTypeFacts(sourceType) & TypeFacts.IsUndefinedOrNull) === (getTypeFacts(targetType) & TypeFacts.IsUndefinedOrNull); + (getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable); let related = callbacks ? compareSignaturesRelated(targetSig, sourceSig, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) : !(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors); @@ -21387,8 +21382,31 @@ namespace ts { return value.base10Value === "0"; } + function getFalsyFlagsOfTypes(types: Type[]): TypeFlags { + let result: TypeFlags = 0; + for (const t of types) { + result |= getFalsyFlags(t); + } + return result; + } + + // Returns the String, Number, Boolean, StringLiteral, NumberLiteral, BooleanLiteral, Void, Undefined, or Null + // flags for the string, number, boolean, "", 0, false, void, undefined, or null types respectively. Returns + // no flags for all other types (including non-falsy literal types). + function getFalsyFlags(type: Type): TypeFlags { + const t = type.flags & TypeFlags.Intersection ? getBaseConstraintOrType(type) : type; + return t.flags & TypeFlags.Union ? getFalsyFlagsOfTypes((t as UnionType).types) : + t.flags & TypeFlags.StringLiteral ? (t as StringLiteralType).value === "" ? TypeFlags.StringLiteral : 0 : + t.flags & TypeFlags.NumberLiteral ? (t as NumberLiteralType).value === 0 ? TypeFlags.NumberLiteral : 0 : + t.flags & TypeFlags.BigIntLiteral ? isZeroBigInt(t as BigIntLiteralType) ? TypeFlags.BigIntLiteral : 0 : + t.flags & TypeFlags.BooleanLiteral ? (t === falseType || t === regularFalseType) ? TypeFlags.BooleanLiteral : 0 : + t.flags & TypeFlags.PossiblyFalsy; + } + function removeDefinitelyFalsyTypes(type: Type): Type { - return filterType(type, t => !!(getTypeFacts(t) & TypeFacts.Truthy)); + return getFalsyFlags(type) & TypeFlags.DefinitelyFalsy ? + filterType(type, t => !(getFalsyFlags(t) & TypeFlags.DefinitelyFalsy)) : + type; } function extractDefinitelyFalsyTypes(type: Type): Type { @@ -21436,7 +21454,14 @@ namespace ts { } function getNonNullableType(type: Type): Type { - return strictNullChecks ? getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; + if (strictNullChecks) { + // First reduce away any constituents that are assignable to 'undefined' or 'null'. This not only eliminates + // 'undefined' and 'null', but also higher-order types such as a type parameter 'U extends undefined | null' + // that isn't eliminated by a NonNullable instantiation. + const reducedType = getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); + return maybeTypeOfKind(reducedType, TypeFlags.Instantiable) ? getGlobalNonNullableTypeInstantiation(reducedType) : reducedType; + } + return type; } function addOptionalTypeMarker(type: Type) { @@ -23526,16 +23551,13 @@ namespace ts { resolved.members.get("bind" as __String) && isTypeSubtypeOf(type, globalFunctionType)); } - function getTypeFacts(type: Type): TypeFacts { - if (type.flags & (TypeFlags.Intersection | TypeFlags.Instantiable)) { - type = getBaseConstraintOfType(type) || unknownType; - } + function getTypeFacts(type: Type, ignoreObjects = false): TypeFacts { const flags = type.flags; - if (flags & (TypeFlags.String | TypeFlags.StringMapping)) { + if (flags & TypeFlags.String) { return strictNullChecks ? TypeFacts.StringStrictFacts : TypeFacts.StringFacts; } - if (flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral)) { - const isEmpty = flags & TypeFlags.StringLiteral && (type as StringLiteralType).value === ""; + if (flags & TypeFlags.StringLiteral) { + const isEmpty = (type as StringLiteralType).value === ""; return strictNullChecks ? isEmpty ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts : isEmpty ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts; @@ -23567,16 +23589,16 @@ namespace ts { (type === falseType || type === regularFalseType) ? TypeFacts.FalseFacts : TypeFacts.TrueFacts; } if (flags & TypeFlags.Object) { + if (ignoreObjects) { + return TypeFacts.AndFactsMask; // This is the identity element for computing type facts of intersection. + } return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(type as ObjectType) ? strictNullChecks ? TypeFacts.EmptyObjectStrictFacts : TypeFacts.EmptyObjectFacts : isFunctionObjectType(type as ObjectType) ? strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts : strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; } - if (flags & TypeFlags.Void) { - return TypeFacts.VoidFacts; - } - if (flags & TypeFlags.Undefined) { + if (flags & (TypeFlags.Void | TypeFlags.Undefined)) { return TypeFacts.UndefinedFacts; } if (flags & TypeFlags.Null) { @@ -23591,29 +23613,31 @@ namespace ts { if (flags & TypeFlags.Never) { return TypeFacts.None; } + if (flags & TypeFlags.Instantiable) { + return !isPatternLiteralType(type) ? getTypeFacts(getBaseConstraintOfType(type) || unknownType, ignoreObjects) : + strictNullChecks ? TypeFacts.NonEmptyStringStrictFacts : TypeFacts.NonEmptyStringFacts; + } if (flags & TypeFlags.Union) { - return reduceLeft((type as UnionType).types, (facts, t) => facts | getTypeFacts(t), TypeFacts.None); + return reduceLeft((type as UnionType).types, (facts, t) => facts | getTypeFacts(t, ignoreObjects), TypeFacts.None); } if (flags & TypeFlags.Intersection) { - return getIntersectionTypeFacts(type as IntersectionType); + // When an intersection contains a primitive type we ignore object type constituents as they are + // presumably type tags. For example, in string & { __kind__: "name" } we ignore the object type. + ignoreObjects ||= maybeTypeOfKind(type, TypeFlags.Primitive); + return getIntersectionTypeFacts(type as IntersectionType, ignoreObjects); } - return TypeFacts.UnknownFacts; + return TypeFacts.All; } - function getIntersectionTypeFacts(type: IntersectionType): TypeFacts { - // When an intersection contains a primitive type we ignore object type constituents as they are - // presumably type tags. For example, in string & { __kind__: "name" } we ignore the object type. - const ignoreObjects = maybeTypeOfKind(type, TypeFlags.Primitive); + function getIntersectionTypeFacts(type: IntersectionType, ignoreObjects: boolean): TypeFacts { // When computing the type facts of an intersection type, certain type facts are computed as `and` // and others are computed as `or`. let oredFacts = TypeFacts.None; let andedFacts = TypeFacts.All; for (const t of type.types) { - if (!(ignoreObjects && t.flags & TypeFlags.Object)) { - const f = getTypeFacts(t); - oredFacts |= f; - andedFacts &= f; - } + const f = getTypeFacts(t, ignoreObjects); + oredFacts |= f; + andedFacts &= f; } return oredFacts & TypeFacts.OrFactsMask | andedFacts & TypeFacts.AndFactsMask; } @@ -23622,10 +23646,7 @@ namespace ts { return filterType(type, t => (getTypeFacts(t) & include) !== 0); } - // This function is similar to getTypeWithFacts, except that in strictNullChecks mode it replaces type - // unknown with the union {} | null | undefined (and reduces that accordingly), and it intersects remaining - // instantiable types with {}, {} | null, or {} | undefined in order to remove null and/or undefined. - function getAdjustedTypeWithFacts(type: Type, facts: TypeFacts) { + function getIntersectionWithFacts(type: Type, facts: TypeFacts) { const reduced = recombineUnknownType(getTypeWithFacts(strictNullChecks && type.flags & TypeFlags.Unknown ? unknownUnionType : type, facts)); if (strictNullChecks) { switch (facts) { @@ -24884,10 +24905,10 @@ namespace ts { function narrowTypeByTruthiness(type: Type, expr: Expression, assumeTrue: boolean): Type { if (isMatchingReference(reference, expr)) { - return getAdjustedTypeWithFacts(type, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy); + return getIntersectionWithFacts(type, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy); } if (strictNullChecks && assumeTrue && optionalChainContainsReference(expr, reference)) { - type = getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); + type = getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); } const access = getDiscriminantPropertyAccess(expr, type); if (access) { @@ -25033,7 +25054,7 @@ namespace ts { // Note that we include any and unknown in the exclusion test because their domain includes null and undefined. const removeNullable = equalsOperator !== assumeTrue && everyType(valueType, t => !!(t.flags & nullableFlags)) || equalsOperator === assumeTrue && everyType(valueType, t => !(t.flags & (TypeFlags.AnyOrUnknown | nullableFlags))); - return removeNullable ? getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; + return removeNullable ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; } function narrowTypeByEquality(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type { @@ -25063,7 +25084,7 @@ namespace ts { valueType.flags & TypeFlags.Null ? assumeTrue ? TypeFacts.EQNull : TypeFacts.NENull : assumeTrue ? TypeFacts.EQUndefined : TypeFacts.NEUndefined; - return getAdjustedTypeWithFacts(type, facts); + return getIntersectionWithFacts(type, facts); } if (assumeTrue) { const filterFn: (t: Type) => boolean = operator === SyntaxKind.EqualsEqualsToken ? @@ -25085,7 +25106,7 @@ namespace ts { const target = getReferenceCandidate(typeOfExpr.expression); if (!isMatchingReference(reference, target)) { if (strictNullChecks && optionalChainContainsReference(target, reference) && assumeTrue === (literal.text !== "undefined")) { - return getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); + return getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); } return type; } @@ -25305,7 +25326,7 @@ namespace ts { const left = getReferenceCandidate(expr.left); if (!isMatchingReference(reference, left)) { if (assumeTrue && strictNullChecks && optionalChainContainsReference(left, reference)) { - return getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); + return getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); } return type; } @@ -25402,7 +25423,7 @@ namespace ts { } if (strictNullChecks && assumeTrue && optionalChainContainsReference(predicateArgument, reference) && !(getTypeFacts(predicate.type) & TypeFacts.EQUndefined)) { - type = getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); + type = getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); } const access = getDiscriminantPropertyAccess(predicateArgument, type); if (access) { @@ -25461,7 +25482,7 @@ namespace ts { function narrowTypeByOptionality(type: Type, expr: Expression, assumePresent: boolean): Type { if (isMatchingReference(reference, expr)) { - return getAdjustedTypeWithFacts(type, assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull); + return getTypeWithFacts(type, assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull); } const access = getDiscriminantPropertyAccess(expr, type); if (access) { @@ -25553,8 +25574,8 @@ namespace ts { const annotationIncludesUndefined = strictNullChecks && declaration.kind === SyntaxKind.Parameter && declaration.initializer && - getTypeFacts(declaredType) & TypeFacts.IsUndefined && - !(getTypeFacts(checkExpression(declaration.initializer)) & TypeFacts.IsUndefined); + getFalsyFlags(declaredType) & TypeFlags.Undefined && + !(getFalsyFlags(checkExpression(declaration.initializer)) & TypeFlags.Undefined); popTypeResolution(); return annotationIncludesUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType; @@ -25911,7 +25932,7 @@ namespace ts { return convertAutoToAny(flowType); } } - else if (!assumeInitialized && !(getTypeFacts(type) & TypeFacts.IsUndefined) && getTypeFacts(flowType) & TypeFacts.IsUndefined) { + else if (!assumeInitialized && !(getFalsyFlags(type) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) { error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol)); // Return the declared type to reduce follow-on errors return type; @@ -28888,23 +28909,23 @@ namespace ts { } function isNullableType(type: Type) { - return !!(getTypeFacts(type) & TypeFacts.IsUndefinedOrNull); + return !!((strictNullChecks ? getFalsyFlags(type) : type.flags) & TypeFlags.Nullable); } function getNonNullableTypeIfNeeded(type: Type) { return isNullableType(type) ? getNonNullableType(type) : type; } - function reportObjectPossiblyNullOrUndefinedError(node: Node, facts: TypeFacts) { - error(node, facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? + function reportObjectPossiblyNullOrUndefinedError(node: Node, flags: TypeFlags) { + error(node, flags & TypeFlags.Undefined ? flags & TypeFlags.Null ? Diagnostics.Object_is_possibly_null_or_undefined : Diagnostics.Object_is_possibly_undefined : Diagnostics.Object_is_possibly_null ); } - function reportCannotInvokePossiblyNullOrUndefinedError(node: Node, facts: TypeFacts) { - error(node, facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? + function reportCannotInvokePossiblyNullOrUndefinedError(node: Node, flags: TypeFlags) { + error(node, flags & TypeFlags.Undefined ? flags & TypeFlags.Null ? Diagnostics.Cannot_invoke_an_object_which_is_possibly_null_or_undefined : Diagnostics.Cannot_invoke_an_object_which_is_possibly_undefined : Diagnostics.Cannot_invoke_an_object_which_is_possibly_null @@ -28914,15 +28935,15 @@ namespace ts { function checkNonNullTypeWithReporter( type: Type, node: Node, - reportError: (node: Node, facts: TypeFacts) => void + reportError: (node: Node, kind: TypeFlags) => void ): Type { if (strictNullChecks && type.flags & TypeFlags.Unknown) { error(node, Diagnostics.Object_is_of_type_unknown); return errorType; } - const facts = getTypeFacts(type); - if (facts & TypeFacts.IsUndefinedOrNull) { - reportError(node, facts); + const kind = (strictNullChecks ? getFalsyFlags(type) : type.flags) & TypeFlags.Nullable; + if (kind) { + reportError(node, kind); const t = getNonNullableType(type); return t.flags & (TypeFlags.Nullable | TypeFlags.Never) ? errorType : t; } @@ -29268,7 +29289,7 @@ namespace ts { assumeUninitialized = true; } const flowType = getFlowTypeOfReference(node, propType, assumeUninitialized ? getOptionalType(propType) : propType); - if (assumeUninitialized && !(getTypeFacts(propType) & TypeFacts.IsUndefined) && getTypeFacts(flowType) & TypeFacts.IsUndefined) { + if (assumeUninitialized && !(getFalsyFlags(propType) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) { error(errorNode, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(prop!)); // TODO: GH#18217 // Return the declared type to reduce follow-on errors return propType; @@ -33255,7 +33276,7 @@ namespace ts { const type = getTypeOfSymbol(symbol); if (strictNullChecks && !(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Never)) && - !(exactOptionalPropertyTypes ? symbol.flags & SymbolFlags.Optional : getTypeFacts(type) & TypeFacts.IsUndefined)) { + !(exactOptionalPropertyTypes ? symbol.flags & SymbolFlags.Optional : getFalsyFlags(type) & TypeFlags.Undefined)) { error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_optional); } } @@ -33692,7 +33713,7 @@ namespace ts { // In strict null checking mode, if a default value of a non-undefined type is specified, remove // undefined from the final type. if (strictNullChecks && - !(getTypeFacts(checkExpression(prop.objectAssignmentInitializer)) & TypeFacts.IsUndefined)) { + !(getFalsyFlags(checkExpression(prop.objectAssignmentInitializer)) & TypeFlags.Undefined)) { sourceType = getTypeWithFacts(sourceType, TypeFacts.NEUndefined); } checkBinaryLikeExpression(prop.name, prop.equalsToken!, prop.objectAssignmentInitializer, checkMode); @@ -34155,7 +34176,7 @@ namespace ts { case SyntaxKind.BarBarToken: case SyntaxKind.BarBarEqualsToken: { const resultType = getTypeFacts(leftType) & TypeFacts.Falsy ? - getUnionType([getNonNullableType(removeDefinitelyFalsyTypes(leftType)), rightType], UnionReduction.Subtype) : + getUnionType([removeDefinitelyFalsyTypes(leftType), rightType], UnionReduction.Subtype) : leftType; if (operator === SyntaxKind.BarBarEqualsToken) { checkAssignmentOperator(rightType); @@ -38113,7 +38134,7 @@ namespace ts { if (isModuleExportsAccessExpression(location)) return; const type = checkTruthinessExpression(location); const isPropertyExpressionCast = isPropertyAccessExpression(location) && isTypeAssertion(location.expression); - if (!(getTypeFacts(type) & TypeFacts.Truthy) || isPropertyExpressionCast) return; + if (getFalsyFlags(type) || isPropertyExpressionCast) return; // While it technically should be invalid for any known-truthy value // to be tested, we de-scope to functions and Promises unreferenced in @@ -40249,7 +40270,7 @@ namespace ts { const propName = (member as PropertyDeclaration).name; if (isIdentifier(propName) || isPrivateIdentifier(propName) || isComputedPropertyName(propName)) { const type = getTypeOfSymbol(getSymbolOfNode(member)); - if (!(type.flags & TypeFlags.AnyOrUnknown || getTypeFacts(type) & TypeFacts.IsUndefined)) { + if (!(type.flags & TypeFlags.AnyOrUnknown || getFalsyFlags(type) & TypeFlags.Undefined)) { if (!constructor || !isPropertyInitializedInConstructor(propName, type, constructor)) { error(member.name, Diagnostics.Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor, declarationNameToString(propName)); } @@ -40275,7 +40296,7 @@ namespace ts { setParent(reference, staticBlock); reference.flowNode = staticBlock.returnFlowNode; const flowType = getFlowTypeOfReference(reference, propType, getOptionalType(propType)); - if (!(getTypeFacts(flowType) & TypeFacts.IsUndefined)) { + if (!(getFalsyFlags(flowType) & TypeFlags.Undefined)) { return true; } } @@ -40291,7 +40312,7 @@ namespace ts { setParent(reference, constructor); reference.flowNode = constructor.returnFlowNode; const flowType = getFlowTypeOfReference(reference, propType, getOptionalType(propType)); - return !(getTypeFacts(flowType) & TypeFacts.IsUndefined); + return !(getFalsyFlags(flowType) & TypeFlags.Undefined); } diff --git a/tests/baselines/reference/discriminatedUnionJsxElement.types b/tests/baselines/reference/discriminatedUnionJsxElement.types index 9057c9c55ab3e..4f7b5a1ccdd9c 100644 --- a/tests/baselines/reference/discriminatedUnionJsxElement.types +++ b/tests/baselines/reference/discriminatedUnionJsxElement.types @@ -14,8 +14,8 @@ function Menu >data : IData const listItemVariant = data.menuItemsVariant ?? ListItemVariant.OneLine; ->listItemVariant : ListItemVariant.OneLine | MenuItemVariant ->data.menuItemsVariant ?? ListItemVariant.OneLine : ListItemVariant.OneLine | MenuItemVariant +>listItemVariant : ListItemVariant.OneLine | NonNullable +>data.menuItemsVariant ?? ListItemVariant.OneLine : ListItemVariant.OneLine | NonNullable >data.menuItemsVariant : MenuItemVariant | undefined >data : IData >menuItemsVariant : MenuItemVariant | undefined diff --git a/tests/baselines/reference/mappedTypes4.types b/tests/baselines/reference/mappedTypes4.types index f96bf1c5e8f48..434fcf1f7e87f 100644 --- a/tests/baselines/reference/mappedTypes4.types +++ b/tests/baselines/reference/mappedTypes4.types @@ -30,14 +30,14 @@ function boxify(obj: T): Boxified { >obj : (T & null) | (T & object) result[k] = { value: obj[k] }; ->result[k] = { value: obj[k] } : { value: (T & object)[Extract]; } +>result[k] = { value: obj[k] } : { value: NonNullable[Extract]; } >result[k] : Boxified[Extract] >result : Boxified >k : Extract ->{ value: obj[k] } : { value: (T & object)[Extract]; } ->value : (T & object)[Extract] ->obj[k] : (T & object)[Extract] ->obj : T & object +>{ value: obj[k] } : { value: NonNullable[Extract]; } +>value : NonNullable[Extract] +>obj[k] : NonNullable[Extract] +>obj : NonNullable >k : Extract } return result; diff --git a/tests/baselines/reference/neverType.js b/tests/baselines/reference/neverType.js index 9d81d49d76a8b..eb7ee33148013 100644 --- a/tests/baselines/reference/neverType.js +++ b/tests/baselines/reference/neverType.js @@ -180,7 +180,7 @@ declare function infiniteLoop1(): void; declare function infiniteLoop2(): never; declare function move1(direction: "up" | "down"): 1 | -1; declare function move2(direction: "up" | "down"): 1 | -1; -declare function check(x: T | undefined): NonNullable; +declare function check(x: T | undefined): T; declare class C { void1(): void; void2(): void; diff --git a/tests/baselines/reference/neverType.types b/tests/baselines/reference/neverType.types index b7e08eb503ad6..7ae38d11f76ce 100644 --- a/tests/baselines/reference/neverType.types +++ b/tests/baselines/reference/neverType.types @@ -112,11 +112,11 @@ function move2(direction: "up" | "down") { } function check(x: T | undefined) { ->check : (x: T | undefined) => NonNullable +>check : (x: T | undefined) => T >x : T | undefined return x || error("Undefined value"); ->x || error("Undefined value") : NonNullable +>x || error("Undefined value") : T >x : T | undefined >error("Undefined value") : never >error : (message: string) => never diff --git a/tests/baselines/reference/nonNullParameterExtendingStringAssignableToString.types b/tests/baselines/reference/nonNullParameterExtendingStringAssignableToString.types index 64c099cfa4e8d..5f9783c5f902f 100644 --- a/tests/baselines/reference/nonNullParameterExtendingStringAssignableToString.types +++ b/tests/baselines/reference/nonNullParameterExtendingStringAssignableToString.types @@ -25,7 +25,7 @@ function fn(one: T, two: U) { foo(two!); >foo(two!) : void >foo : (p: string) => void ->two! : U +>two! : NonNullable >two : U foo(three!); // this line is the important one diff --git a/tests/baselines/reference/nonNullableTypes1.js b/tests/baselines/reference/nonNullableTypes1.js deleted file mode 100644 index 51d4918aa60a1..0000000000000 --- a/tests/baselines/reference/nonNullableTypes1.js +++ /dev/null @@ -1,85 +0,0 @@ -//// [nonNullableTypes1.ts] -function f1(x: T) { - let y = x || "hello"; // NonNullable | string -} - -function error(): never { - throw new Error(); -} - -function f2(x: T) { // NonNullable - return x || error(); -} - -function f3(x: unknown) { - let y = x!; // {} -} - -function f4(obj: T) { - if (obj?.x === "hello") { - obj; // NonNullable - } - if (obj?.x) { - obj; // NonNullable - } - if (typeof obj?.x === "string") { - obj; // NonNullable - } -} - -class A { - x = "hello"; - foo() { - let zz = this?.x; // string - } -} - - -//// [nonNullableTypes1.js] -"use strict"; -function f1(x) { - var y = x || "hello"; // NonNullable | string -} -function error() { - throw new Error(); -} -function f2(x) { - return x || error(); -} -function f3(x) { - var y = x; // {} -} -function f4(obj) { - if ((obj === null || obj === void 0 ? void 0 : obj.x) === "hello") { - obj; // NonNullable - } - if (obj === null || obj === void 0 ? void 0 : obj.x) { - obj; // NonNullable - } - if (typeof (obj === null || obj === void 0 ? void 0 : obj.x) === "string") { - obj; // NonNullable - } -} -var A = /** @class */ (function () { - function A() { - this.x = "hello"; - } - A.prototype.foo = function () { - var zz = this === null || this === void 0 ? void 0 : this.x; // string - }; - return A; -}()); - - -//// [nonNullableTypes1.d.ts] -declare function f1(x: T): void; -declare function error(): never; -declare function f2(x: T): NonNullable; -declare function f3(x: unknown): void; -declare function f4(obj: T): void; -declare class A { - x: string; - foo(): void; -} diff --git a/tests/baselines/reference/nonNullableTypes1.symbols b/tests/baselines/reference/nonNullableTypes1.symbols deleted file mode 100644 index 7737d22f68027..0000000000000 --- a/tests/baselines/reference/nonNullableTypes1.symbols +++ /dev/null @@ -1,89 +0,0 @@ -=== tests/cases/compiler/nonNullableTypes1.ts === -function f1(x: T) { ->f1 : Symbol(f1, Decl(nonNullableTypes1.ts, 0, 0)) ->T : Symbol(T, Decl(nonNullableTypes1.ts, 0, 12)) ->x : Symbol(x, Decl(nonNullableTypes1.ts, 0, 15)) ->T : Symbol(T, Decl(nonNullableTypes1.ts, 0, 12)) - - let y = x || "hello"; // NonNullable | string ->y : Symbol(y, Decl(nonNullableTypes1.ts, 1, 7)) ->x : Symbol(x, Decl(nonNullableTypes1.ts, 0, 15)) -} - -function error(): never { ->error : Symbol(error, Decl(nonNullableTypes1.ts, 2, 1)) - - throw new Error(); ->Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) -} - -function f2(x: T) { // NonNullable ->f2 : Symbol(f2, Decl(nonNullableTypes1.ts, 6, 1)) ->T : Symbol(T, Decl(nonNullableTypes1.ts, 8, 12)) ->x : Symbol(x, Decl(nonNullableTypes1.ts, 8, 15)) ->T : Symbol(T, Decl(nonNullableTypes1.ts, 8, 12)) - - return x || error(); ->x : Symbol(x, Decl(nonNullableTypes1.ts, 8, 15)) ->error : Symbol(error, Decl(nonNullableTypes1.ts, 2, 1)) -} - -function f3(x: unknown) { ->f3 : Symbol(f3, Decl(nonNullableTypes1.ts, 10, 1)) ->x : Symbol(x, Decl(nonNullableTypes1.ts, 12, 12)) - - let y = x!; // {} ->y : Symbol(y, Decl(nonNullableTypes1.ts, 13, 7)) ->x : Symbol(x, Decl(nonNullableTypes1.ts, 12, 12)) -} - -function f4(obj: T) { ->f4 : Symbol(f4, Decl(nonNullableTypes1.ts, 14, 1)) ->T : Symbol(T, Decl(nonNullableTypes1.ts, 16, 12)) ->x : Symbol(x, Decl(nonNullableTypes1.ts, 16, 23)) ->obj : Symbol(obj, Decl(nonNullableTypes1.ts, 16, 49)) ->T : Symbol(T, Decl(nonNullableTypes1.ts, 16, 12)) - - if (obj?.x === "hello") { ->obj?.x : Symbol(x, Decl(nonNullableTypes1.ts, 16, 23)) ->obj : Symbol(obj, Decl(nonNullableTypes1.ts, 16, 49)) ->x : Symbol(x, Decl(nonNullableTypes1.ts, 16, 23)) - - obj; // NonNullable ->obj : Symbol(obj, Decl(nonNullableTypes1.ts, 16, 49)) - } - if (obj?.x) { ->obj?.x : Symbol(x, Decl(nonNullableTypes1.ts, 16, 23)) ->obj : Symbol(obj, Decl(nonNullableTypes1.ts, 16, 49)) ->x : Symbol(x, Decl(nonNullableTypes1.ts, 16, 23)) - - obj; // NonNullable ->obj : Symbol(obj, Decl(nonNullableTypes1.ts, 16, 49)) - } - if (typeof obj?.x === "string") { ->obj?.x : Symbol(x, Decl(nonNullableTypes1.ts, 16, 23)) ->obj : Symbol(obj, Decl(nonNullableTypes1.ts, 16, 49)) ->x : Symbol(x, Decl(nonNullableTypes1.ts, 16, 23)) - - obj; // NonNullable ->obj : Symbol(obj, Decl(nonNullableTypes1.ts, 16, 49)) - } -} - -class A { ->A : Symbol(A, Decl(nonNullableTypes1.ts, 26, 1)) - - x = "hello"; ->x : Symbol(A.x, Decl(nonNullableTypes1.ts, 28, 9)) - - foo() { ->foo : Symbol(A.foo, Decl(nonNullableTypes1.ts, 29, 16)) - - let zz = this?.x; // string ->zz : Symbol(zz, Decl(nonNullableTypes1.ts, 31, 11)) ->this?.x : Symbol(A.x, Decl(nonNullableTypes1.ts, 28, 9)) ->this : Symbol(A, Decl(nonNullableTypes1.ts, 26, 1)) ->x : Symbol(A.x, Decl(nonNullableTypes1.ts, 28, 9)) - } -} - diff --git a/tests/baselines/reference/nonNullableTypes1.types b/tests/baselines/reference/nonNullableTypes1.types deleted file mode 100644 index 3d319114e794c..0000000000000 --- a/tests/baselines/reference/nonNullableTypes1.types +++ /dev/null @@ -1,95 +0,0 @@ -=== tests/cases/compiler/nonNullableTypes1.ts === -function f1(x: T) { ->f1 : (x: T) => void ->x : T - - let y = x || "hello"; // NonNullable | string ->y : string | NonNullable ->x || "hello" : "hello" | NonNullable ->x : T ->"hello" : "hello" -} - -function error(): never { ->error : () => never - - throw new Error(); ->new Error() : Error ->Error : ErrorConstructor -} - -function f2(x: T) { // NonNullable ->f2 : (x: T) => NonNullable ->x : T - - return x || error(); ->x || error() : NonNullable ->x : T ->error() : never ->error : () => never -} - -function f3(x: unknown) { ->f3 : (x: unknown) => void ->x : unknown - - let y = x!; // {} ->y : {} ->x! : {} ->x : unknown -} - -function f4(obj: T) { ->f4 : (obj: T) => void ->x : string ->obj : T - - if (obj?.x === "hello") { ->obj?.x === "hello" : boolean ->obj?.x : string | undefined ->obj : { x: string; } | undefined ->x : string | undefined ->"hello" : "hello" - - obj; // NonNullable ->obj : NonNullable - } - if (obj?.x) { ->obj?.x : string | undefined ->obj : { x: string; } | undefined ->x : string | undefined - - obj; // NonNullable ->obj : NonNullable - } - if (typeof obj?.x === "string") { ->typeof obj?.x === "string" : boolean ->typeof obj?.x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->obj?.x : string | undefined ->obj : { x: string; } | undefined ->x : string | undefined ->"string" : "string" - - obj; // NonNullable ->obj : NonNullable - } -} - -class A { ->A : A - - x = "hello"; ->x : string ->"hello" : "hello" - - foo() { ->foo : () => void - - let zz = this?.x; // string ->zz : string ->this?.x : string ->this : this ->x : string - } -} - diff --git a/tests/baselines/reference/nullishCoalescingOperator2.types b/tests/baselines/reference/nullishCoalescingOperator2.types index 085b3de8d5987..dd1e31c4038c4 100644 --- a/tests/baselines/reference/nullishCoalescingOperator2.types +++ b/tests/baselines/reference/nullishCoalescingOperator2.types @@ -75,8 +75,8 @@ const aa6 = a6 ?? 'whatever' >'whatever' : "whatever" const aa7 = a7 ?? 'whatever' ->aa7 : {} ->a7 ?? 'whatever' : {} +>aa7 : unknown +>a7 ?? 'whatever' : unknown >a7 : unknown >'whatever' : "whatever" diff --git a/tests/baselines/reference/nullishCoalescingOperator_es2020.types b/tests/baselines/reference/nullishCoalescingOperator_es2020.types index aec3adb3d462a..2dead6366b7a6 100644 --- a/tests/baselines/reference/nullishCoalescingOperator_es2020.types +++ b/tests/baselines/reference/nullishCoalescingOperator_es2020.types @@ -75,8 +75,8 @@ const aa6 = a6 ?? 'whatever' >'whatever' : "whatever" const aa7 = a7 ?? 'whatever' ->aa7 : {} ->a7 ?? 'whatever' : {} +>aa7 : unknown +>a7 ?? 'whatever' : unknown >a7 : unknown >'whatever' : "whatever" diff --git a/tests/baselines/reference/privateIdentifierChain.1.types b/tests/baselines/reference/privateIdentifierChain.1.types index 34deba67625a5..faf9a763c04f3 100644 --- a/tests/baselines/reference/privateIdentifierChain.1.types +++ b/tests/baselines/reference/privateIdentifierChain.1.types @@ -28,10 +28,10 @@ class A { this?.getA().#b; // Error >this?.getA().#b : A | undefined ->this?.getA() : A ->this?.getA : () => A +>this?.getA() : A | undefined +>this?.getA : (() => A) | undefined >this : this ->getA : () => A +>getA : (() => A) | undefined } } diff --git a/tests/baselines/reference/simplifyingConditionalWithInteriorConditionalIsRelated.types b/tests/baselines/reference/simplifyingConditionalWithInteriorConditionalIsRelated.types index d9b814a227490..52e8ef8f14fbe 100644 --- a/tests/baselines/reference/simplifyingConditionalWithInteriorConditionalIsRelated.types +++ b/tests/baselines/reference/simplifyingConditionalWithInteriorConditionalIsRelated.types @@ -15,7 +15,7 @@ function JustConditional(): ConditionalType { >JustConditional : () => ConditionalType return ConditionalOrUndefined()!; // shouldn't error ->ConditionalOrUndefined()! : ConditionalType +>ConditionalOrUndefined()! : NonNullable> >ConditionalOrUndefined() : ConditionalType | undefined >ConditionalOrUndefined : () => ConditionalType | undefined } diff --git a/tests/cases/compiler/nonNullableTypes1.ts b/tests/cases/compiler/nonNullableTypes1.ts deleted file mode 100644 index 7006c3c1fc698..0000000000000 --- a/tests/cases/compiler/nonNullableTypes1.ts +++ /dev/null @@ -1,37 +0,0 @@ -// @strict: true -// @declaration: true - -function f1(x: T) { - let y = x || "hello"; // NonNullable | string -} - -function error(): never { - throw new Error(); -} - -function f2(x: T) { // NonNullable - return x || error(); -} - -function f3(x: unknown) { - let y = x!; // {} -} - -function f4(obj: T) { - if (obj?.x === "hello") { - obj; // NonNullable - } - if (obj?.x) { - obj; // NonNullable - } - if (typeof obj?.x === "string") { - obj; // NonNullable - } -} - -class A { - x = "hello"; - foo() { - let zz = this?.x; // string - } -}