diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2b8244ca06c..ef107c2bc68 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15845,17 +15845,35 @@ namespace ts { }); } - function checkNonNullExpression(node: Expression | QualifiedName) { - return checkNonNullType(checkExpression(node), node); + function checkNonNullExpression( + node: Expression | QualifiedName, + nullDiagnostic?: DiagnosticMessage, + undefinedDiagnostic?: DiagnosticMessage, + nullOrUndefinedDiagnostic?: DiagnosticMessage, + ) { + return checkNonNullType( + checkExpression(node), + node, + nullDiagnostic, + undefinedDiagnostic, + nullOrUndefinedDiagnostic + ); } - function checkNonNullType(type: Type, errorNode: Node): Type { + function checkNonNullType( + type: Type, + node: Node, + nullDiagnostic?: DiagnosticMessage, + undefinedDiagnostic?: DiagnosticMessage, + nullOrUndefinedDiagnostic?: DiagnosticMessage + ): Type { const kind = (strictNullChecks ? getFalsyFlags(type) : type.flags) & TypeFlags.Nullable; if (kind) { - error(errorNode, kind & TypeFlags.Undefined ? kind & TypeFlags.Null ? - Diagnostics.Object_is_possibly_null_or_undefined : - Diagnostics.Object_is_possibly_undefined : - Diagnostics.Object_is_possibly_null); + error(node, kind & TypeFlags.Undefined ? kind & TypeFlags.Null ? + (nullOrUndefinedDiagnostic || Diagnostics.Object_is_possibly_null_or_undefined) : + (undefinedDiagnostic || Diagnostics.Object_is_possibly_undefined) : + (nullDiagnostic || Diagnostics.Object_is_possibly_null) + ); const t = getNonNullableType(type); return t.flags & (TypeFlags.Nullable | TypeFlags.Never) ? unknownType : t; } @@ -17364,7 +17382,13 @@ namespace ts { return resolveUntypedCall(node); } - const funcType = checkNonNullExpression(node.expression); + const funcType = checkNonNullExpression( + node.expression, + Diagnostics.Cannot_invoke_an_object_which_is_possibly_null, + Diagnostics.Cannot_invoke_an_object_which_is_possibly_undefined, + Diagnostics.Cannot_invoke_an_object_which_is_possibly_null_or_undefined + ); + if (funcType === silentNeverType) { return silentNeverSignature; } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index d4641184f45..4fa32251549 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2288,7 +2288,18 @@ "category": "Error", "code": 2720 }, - + "Cannot invoke an object which is possibly 'null'.": { + "category": "Error", + "code": 2721 + }, + "Cannot invoke an object which is possibly 'undefined'.": { + "category": "Error", + "code": 2722 + }, + "Cannot invoke an object which is possibly 'null' or 'undefined'.": { + "category": "Error", + "code": 2723 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", "code": 4000 diff --git a/tests/baselines/reference/nullableFunctionError.errors.txt b/tests/baselines/reference/nullableFunctionError.errors.txt new file mode 100644 index 00000000000..074afdaee4f --- /dev/null +++ b/tests/baselines/reference/nullableFunctionError.errors.txt @@ -0,0 +1,17 @@ +tests/cases/compiler/nullableFunctionError.ts(1,1): error TS2721: Cannot invoke an object which is possibly 'null'. +tests/cases/compiler/nullableFunctionError.ts(2,1): error TS2722: Cannot invoke an object which is possibly 'undefined'. +tests/cases/compiler/nullableFunctionError.ts(4,1): error TS2723: Cannot invoke an object which is possibly 'null' or 'undefined'. + + +==== tests/cases/compiler/nullableFunctionError.ts (3 errors) ==== + null(); + ~~~~ +!!! error TS2721: Cannot invoke an object which is possibly 'null'. + undefined(); + ~~~~~~~~~ +!!! error TS2722: Cannot invoke an object which is possibly 'undefined'. + let f: null | undefined; + f(); + ~ +!!! error TS2723: Cannot invoke an object which is possibly 'null' or 'undefined'. + \ No newline at end of file diff --git a/tests/baselines/reference/nullableFunctionError.js b/tests/baselines/reference/nullableFunctionError.js new file mode 100644 index 00000000000..a8b1f28c51a --- /dev/null +++ b/tests/baselines/reference/nullableFunctionError.js @@ -0,0 +1,12 @@ +//// [nullableFunctionError.ts] +null(); +undefined(); +let f: null | undefined; +f(); + + +//// [nullableFunctionError.js] +null(); +undefined(); +var f; +f(); diff --git a/tests/baselines/reference/nullableFunctionError.symbols b/tests/baselines/reference/nullableFunctionError.symbols new file mode 100644 index 00000000000..cb066bdb32d --- /dev/null +++ b/tests/baselines/reference/nullableFunctionError.symbols @@ -0,0 +1,11 @@ +=== tests/cases/compiler/nullableFunctionError.ts === +null(); +undefined(); +>undefined : Symbol(undefined) + +let f: null | undefined; +>f : Symbol(f, Decl(nullableFunctionError.ts, 2, 3)) + +f(); +>f : Symbol(f, Decl(nullableFunctionError.ts, 2, 3)) + diff --git a/tests/baselines/reference/nullableFunctionError.types b/tests/baselines/reference/nullableFunctionError.types new file mode 100644 index 00000000000..97697fbb564 --- /dev/null +++ b/tests/baselines/reference/nullableFunctionError.types @@ -0,0 +1,17 @@ +=== tests/cases/compiler/nullableFunctionError.ts === +null(); +>null() : any +>null : null + +undefined(); +>undefined() : any +>undefined : undefined + +let f: null | undefined; +>f : null | undefined +>null : null + +f(); +>f() : any +>f : null | undefined + diff --git a/tests/cases/compiler/nullableFunctionError.ts b/tests/cases/compiler/nullableFunctionError.ts new file mode 100644 index 00000000000..5477d7fa29a --- /dev/null +++ b/tests/cases/compiler/nullableFunctionError.ts @@ -0,0 +1,6 @@ +// @strictNullChecks: true + +null(); +undefined(); +let f: null | undefined; +f();