Nullable errors on unconstrained generic types in strictNullChecks mode

This commit is contained in:
Anders Hejlsberg 2024-07-26 13:47:47 -07:00
parent b9b07c412f
commit 9aec49b42b

View File

@ -1226,8 +1226,11 @@ export const enum TypeFacts {
Falsy = 1 << 23, // !x
IsUndefined = 1 << 24, // Contains undefined or intersection with undefined
IsNull = 1 << 25, // Contains null or intersection with null
IsPossiblyUndefined = 1 << 26, // Possibly undefined
IsPossiblyNull = 1 << 27, // Possibly null
IsUndefinedOrNull = IsUndefined | IsNull,
All = (1 << 27) - 1,
IsPossiblyUndefinedOrNull = IsPossiblyUndefined | IsPossiblyNull,
All = (1 << 29) - 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.
@ -1270,11 +1273,12 @@ export const enum TypeFacts {
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 | IsUndefined | IsPossiblyUndefined,
NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy | IsNull | IsPossiblyNull,
EmptyObjectStrictFacts = All & ~(EQUndefined | EQNull | EQUndefinedOrNull | IsUndefinedOrNull | IsPossiblyUndefinedOrNull),
EmptyObjectFacts = All & ~(IsUndefinedOrNull | IsPossiblyUndefinedOrNull),
UnknownStrictFacts = All & ~IsUndefinedOrNull,
UnknownFacts = All & ~(IsUndefinedOrNull | IsPossiblyUndefinedOrNull),
AllTypeofNE = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | NEUndefined,
// Masks
OrFactsMask = TypeofEQFunction | TypeofNEObject,
@ -27477,7 +27481,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (flags & TypeFlags.Intersection) {
return getIntersectionTypeFacts(type as IntersectionType, callerOnlyNeeds);
}
return TypeFacts.UnknownFacts;
return strictNullChecks && flags & TypeFlags.Unknown ? TypeFacts.UnknownStrictFacts : TypeFacts.UnknownFacts;
}
function getIntersectionTypeFacts(type: IntersectionType, callerOnlyNeeds: TypeFacts): TypeFacts {
@ -33699,7 +33703,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
error(
node,
facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ?
facts & TypeFacts.IsPossiblyUndefined ? facts & TypeFacts.IsPossiblyNull ?
Diagnostics._0_is_possibly_null_or_undefined :
Diagnostics._0_is_possibly_undefined :
Diagnostics._0_is_possibly_null,
@ -33709,7 +33713,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
else {
error(
node,
facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ?
facts & TypeFacts.IsPossiblyUndefined ? facts & TypeFacts.IsPossiblyNull ?
Diagnostics.Object_is_possibly_null_or_undefined :
Diagnostics.Object_is_possibly_undefined :
Diagnostics.Object_is_possibly_null,
@ -33720,7 +33724,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function reportCannotInvokePossiblyNullOrUndefinedError(node: Node, facts: TypeFacts) {
error(
node,
facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ?
facts & TypeFacts.IsPossiblyUndefined ? facts & TypeFacts.IsPossiblyNull ?
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,
@ -33743,8 +33747,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
error(node, Diagnostics.Object_is_of_type_unknown);
return errorType;
}
const facts = getTypeFacts(type, TypeFacts.IsUndefinedOrNull);
if (facts & TypeFacts.IsUndefinedOrNull) {
const facts = getTypeFacts(type, TypeFacts.IsPossiblyUndefinedOrNull);
if (facts & TypeFacts.IsPossiblyUndefinedOrNull) {
reportError(node, facts);
const t = getNonNullableType(type);
return t.flags & (TypeFlags.Nullable | TypeFlags.Never) ? errorType : t;