Skip to content

Commit bcc9220

Browse files
committed
Improve typing of && operator with --strictNullChecks
1 parent 3853555 commit bcc9220

File tree

2 files changed

+23
-28
lines changed

2 files changed

+23
-28
lines changed

src/compiler/checker.ts

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2844,7 +2844,7 @@ namespace ts {
28442844
}
28452845
// In strict null checking mode, if a default value of a non-undefined type is specified, remove
28462846
// undefined from the final type.
2847-
if (strictNullChecks && declaration.initializer && !(getNullableKind(checkExpressionCached(declaration.initializer)) & TypeFlags.Undefined)) {
2847+
if (strictNullChecks && declaration.initializer && !(getCombinedTypeFlags(checkExpressionCached(declaration.initializer)) & TypeFlags.Undefined)) {
28482848
type = getTypeWithFacts(type, TypeFacts.NEUndefined);
28492849
}
28502850
return type;
@@ -2887,7 +2887,7 @@ namespace ts {
28872887
}
28882888

28892889
function addOptionality(type: Type, optional: boolean): Type {
2890-
return strictNullChecks && optional ? addNullableKind(type, TypeFlags.Undefined) : type;
2890+
return strictNullChecks && optional ? addTypeKind(type, TypeFlags.Undefined) : type;
28912891
}
28922892

28932893
// Return the inferred type for a variable, parameter, or property declaration
@@ -3222,7 +3222,7 @@ namespace ts {
32223222
if (!links.type) {
32233223
const type = createObjectType(TypeFlags.Anonymous, symbol);
32243224
links.type = strictNullChecks && symbol.flags & SymbolFlags.Optional ?
3225-
addNullableKind(type, TypeFlags.Undefined) : type;
3225+
addTypeKind(type, TypeFlags.Undefined) : type;
32263226
}
32273227
return links.type;
32283228
}
@@ -6746,7 +6746,7 @@ namespace ts {
67466746
return getUnionType(types);
67476747
}
67486748
const supertype = forEach(primaryTypes, t => isSupertypeOfEach(t, primaryTypes) ? t : undefined);
6749-
return supertype && addNullableKind(supertype, getCombinedFlagsOfTypes(types) & TypeFlags.Nullable);
6749+
return supertype && addTypeKind(supertype, getCombinedFlagsOfTypes(types) & TypeFlags.Nullable);
67506750
}
67516751

67526752
function reportNoCommonSupertypeError(types: Type[], errorLocation: Node, errorMessageChainHead: DiagnosticMessageChain): void {
@@ -6817,28 +6817,22 @@ namespace ts {
68176817
return !!(type.flags & TypeFlags.Tuple);
68186818
}
68196819

6820-
function getNullableKind(type: Type): TypeFlags {
6821-
let flags = type.flags;
6822-
if (flags & TypeFlags.Union) {
6823-
for (const t of (type as UnionType).types) {
6824-
flags |= t.flags;
6825-
}
6826-
}
6827-
return flags & TypeFlags.Nullable;
6820+
function getCombinedTypeFlags(type: Type): TypeFlags {
6821+
return type.flags & TypeFlags.Union ? getCombinedFlagsOfTypes((<UnionType>type).types) : type.flags;
68286822
}
68296823

6830-
function addNullableKind(type: Type, kind: TypeFlags): Type {
6831-
if ((getNullableKind(type) & kind) !== kind) {
6832-
const types = [type];
6833-
if (kind & TypeFlags.Undefined) {
6834-
types.push(undefinedType);
6835-
}
6836-
if (kind & TypeFlags.Null) {
6837-
types.push(nullType);
6838-
}
6839-
type = getUnionType(types);
6824+
function addTypeKind(type: Type, kind: TypeFlags) {
6825+
if ((getCombinedTypeFlags(type) & kind) === kind) {
6826+
return type;
68406827
}
6841-
return type;
6828+
const types = [type];
6829+
if (kind & TypeFlags.String) types.push(stringType);
6830+
if (kind & TypeFlags.Number) types.push(numberType);
6831+
if (kind & TypeFlags.Boolean) types.push(booleanType);
6832+
if (kind & TypeFlags.Void) types.push(voidType);
6833+
if (kind & TypeFlags.Undefined) types.push(undefinedType);
6834+
if (kind & TypeFlags.Null) types.push(nullType);
6835+
return getUnionType(types);
68426836
}
68436837

68446838
function getNonNullableType(type: Type): Type {
@@ -7667,7 +7661,7 @@ namespace ts {
76677661
if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
76687662
return declaredType;
76697663
}
7670-
const initialType = assumeInitialized ? declaredType : addNullableKind(declaredType, TypeFlags.Undefined);
7664+
const initialType = assumeInitialized ? declaredType : addTypeKind(declaredType, TypeFlags.Undefined);
76717665
const visitedFlowStart = visitedFlowCount;
76727666
const result = getTypeAtFlowNode(reference.flowNode);
76737667
visitedFlowCount = visitedFlowStart;
@@ -8163,7 +8157,7 @@ namespace ts {
81638157
getRootDeclaration(declaration).kind === SyntaxKind.Parameter || isInAmbientContext(declaration) ||
81648158
!isDeclarationIncludedInFlow(node, declaration, includeOuterFunctions);
81658159
const flowType = getFlowTypeOfReference(node, type, assumeInitialized, includeOuterFunctions);
8166-
if (!assumeInitialized && !(getNullableKind(type) & TypeFlags.Undefined) && getNullableKind(flowType) & TypeFlags.Undefined) {
8160+
if (!assumeInitialized && !(getCombinedTypeFlags(type) & TypeFlags.Undefined) && getCombinedTypeFlags(flowType) & TypeFlags.Undefined) {
81678161
error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol));
81688162
// Return the declared type to reduce follow-on errors
81698163
return type;
@@ -9945,7 +9939,7 @@ namespace ts {
99459939
function checkNonNullExpression(node: Expression | QualifiedName) {
99469940
const type = checkExpression(node);
99479941
if (strictNullChecks) {
9948-
const kind = getNullableKind(type);
9942+
const kind = getCombinedTypeFlags(type) & TypeFlags.Nullable;
99499943
if (kind) {
99509944
error(node, kind & TypeFlags.Undefined ? kind & TypeFlags.Null ?
99519945
Diagnostics.Object_is_possibly_null_or_undefined :
@@ -11485,7 +11479,7 @@ namespace ts {
1148511479
if (strictNullChecks) {
1148611480
const declaration = symbol.valueDeclaration;
1148711481
if (declaration && (<VariableLikeDeclaration>declaration).initializer) {
11488-
return addNullableKind(type, TypeFlags.Undefined);
11482+
return addTypeKind(type, TypeFlags.Undefined);
1148911483
}
1149011484
}
1149111485
return type;
@@ -12411,7 +12405,7 @@ namespace ts {
1241112405
case SyntaxKind.InKeyword:
1241212406
return checkInExpression(left, right, leftType, rightType);
1241312407
case SyntaxKind.AmpersandAmpersandToken:
12414-
return strictNullChecks ? addNullableKind(rightType, getNullableKind(leftType)) : rightType;
12408+
return strictNullChecks ? addTypeKind(rightType, getCombinedTypeFlags(leftType) & TypeFlags.Falsy) : rightType;
1241512409
case SyntaxKind.BarBarToken:
1241612410
return getUnionType([getNonNullableType(leftType), rightType]);
1241712411
case SyntaxKind.EqualsToken:

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2209,6 +2209,7 @@ namespace ts {
22092209

22102210
/* @internal */
22112211
Nullable = Undefined | Null,
2212+
Falsy = String | Number | Boolean | Void | Undefined | Null,
22122213
/* @internal */
22132214
Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null | Never,
22142215
/* @internal */

0 commit comments

Comments
 (0)