diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0d4c8c7459df3..d3367776dec35 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -35540,8 +35540,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const functionFlags = getFunctionFlags(func); const type = returnType && unwrapReturnType(returnType, functionFlags); - // Functions with with an explicitly specified 'void' or 'any' return type don't need any return expressions. - if (type && maybeTypeOfKind(type, TypeFlags.Any | TypeFlags.Void)) { + // Functions with an explicitly specified 'undefined, 'void' or 'any' return type don't need any return expressions. + if (type && maybeTypeOfKind(type, TypeFlags.Undefined | TypeFlags.Void | TypeFlags.Any)) { return; } @@ -35560,9 +35560,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (type && !hasExplicitReturn) { // minimal check: function has syntactic return type annotation and no explicit return statements in the body // this function does not conform to the specification. - error(errorNode, Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value); + if (strictNullChecks) { + error(errorNode, Diagnostics.A_function_whose_declared_type_is_neither_undefined_void_nor_any_must_return_a_value); + } + else { + error(errorNode, Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value); + } } - else if (type && strictNullChecks && !isTypeAssignableTo(undefinedType, type)) { + else if (type && strictNullChecks) { error(errorNode, Diagnostics.Function_lacks_ending_return_statement_and_return_type_does_not_include_undefined); } else if (compilerOptions.noImplicitReturns) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 8a3f57b764378..4562b7e738e3e 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3611,6 +3611,10 @@ "category": "Error", "code": 2846 }, + "A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.": { + "category": "Error", + "code": 2847 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", @@ -6718,7 +6722,7 @@ "category": "Suggestion", "code": 80010 }, - + "Add missing 'super()' call": { "category": "Message", "code": 90001 diff --git a/src/services/codefixes/returnValueCorrect.ts b/src/services/codefixes/returnValueCorrect.ts index 1492e6377ce26..d3d0945959483 100644 --- a/src/services/codefixes/returnValueCorrect.ts +++ b/src/services/codefixes/returnValueCorrect.ts @@ -52,6 +52,7 @@ const fixRemoveBracesFromArrowFunctionBody = "fixRemoveBracesFromArrowFunctionBo const fixIdWrapTheBlockWithParen = "fixWrapTheBlockWithParen"; const errorCodes = [ Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value.code, + Diagnostics.A_function_whose_declared_type_is_neither_undefined_void_nor_any_must_return_a_value.code, Diagnostics.Type_0_is_not_assignable_to_type_1.code, Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code ]; @@ -214,6 +215,7 @@ function getInfo(checker: TypeChecker, sourceFile: SourceFile, position: number, const declaration = findAncestor(node.parent, isFunctionLikeDeclaration); switch (errorCode) { case Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value.code: + case Diagnostics.A_function_whose_declared_type_is_neither_undefined_void_nor_any_must_return_a_value.code: if (!declaration || !declaration.body || !declaration.type || !rangeContainsRange(declaration.type, node)) return undefined; return getFixInfo(checker, declaration, checker.getTypeFromTypeNode(declaration.type), /* isFunctionType */ false); case Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code: diff --git a/tests/baselines/reference/controlFlowGenericTypes.errors.txt b/tests/baselines/reference/controlFlowGenericTypes.errors.txt index 16ec73b1b4a65..4686e36af6091 100644 --- a/tests/baselines/reference/controlFlowGenericTypes.errors.txt +++ b/tests/baselines/reference/controlFlowGenericTypes.errors.txt @@ -2,7 +2,7 @@ tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts(49,15): error TS2 tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts(55,15): error TS2345: Argument of type 'undefined' is not assignable to parameter of type 'Box'. tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts(81,11): error TS2339: Property 'foo' does not exist on type 'MyUnion'. Property 'foo' does not exist on type 'AA'. -tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts(90,44): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. +tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts(90,44): error TS2847: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts(91,11): error TS2339: Property 'foo' does not exist on type 'MyUnion'. Property 'foo' does not exist on type 'AA'. tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts(156,16): error TS18048: 'obj' is possibly 'undefined'. @@ -109,7 +109,7 @@ tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts(168,9): error TS1 const fn2 = (value: T): MyUnion => { ~~~~~~~ -!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. +!!! error TS2847: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. value.foo; // Error ~~~ !!! error TS2339: Property 'foo' does not exist on type 'MyUnion'. diff --git a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.errors.txt b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.errors.txt index efbdcb8290c56..f4466e0b869e4 100644 --- a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.errors.txt +++ b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.errors.txt @@ -1,11 +1,12 @@ tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(1,16): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(99,17): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. -tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(104,16): error TS2378: A 'get' accessor must return a value. -tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(126,15): error TS18050: The value 'undefined' cannot be used here. -tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(127,5): error TS1003: Identifier expected. +tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(107,17): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. +tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(112,16): error TS2378: A 'get' accessor must return a value. +tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(134,15): error TS18050: The value 'undefined' cannot be used here. +tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(135,5): error TS1003: Identifier expected. -==== tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts (5 errors) ==== +==== tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts (6 errors) ==== function f1(): string { ~~~~~~ !!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. @@ -40,12 +41,12 @@ tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(127,5): e return null; } - function f8(): void { + function f8(): any { // Fine since are typed any. return; } - function f9(): void { + function f9(): any { // Fine since we are typed any and return undefined return undefined; } @@ -112,6 +113,16 @@ tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(127,5): e // Not okay; union does not contain void or any } + function f22(): undefined { + // Okay; return type allows implicit return of undefined + } + + function f23(): undefined | number { + ~~~~~~~~~~~~~~~~~~ +!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. + // Error; because `undefined | number` becomes `number` without strictNullChecks. + } + class C { public get m1() { ~~ @@ -143,4 +154,5 @@ tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(127,5): e } ~ !!! error TS1003: Identifier expected. - } \ No newline at end of file + } + \ No newline at end of file diff --git a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.js b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.js index a0cfa3f9fcea3..4cc59397c5e06 100644 --- a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.js +++ b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.js @@ -31,12 +31,12 @@ function f7(): void { return null; } -function f8(): void { +function f8(): any { // Fine since are typed any. return; } -function f9(): void { +function f9(): any { // Fine since we are typed any and return undefined return undefined; } @@ -101,6 +101,14 @@ function f21(): number | string { // Not okay; union does not contain void or any } +function f22(): undefined { + // Okay; return type allows implicit return of undefined +} + +function f23(): undefined | number { + // Error; because `undefined | number` becomes `number` without strictNullChecks. +} + class C { public get m1() { // Errors; get accessors must return a value. @@ -126,7 +134,8 @@ class C { throw null; throw undefined. } -} +} + //// [functionsMissingReturnStatementsAndExpressions.js] function f1() { @@ -209,6 +218,12 @@ function f20() { function f21() { // Not okay; union does not contain void or any } +function f22() { + // Okay; return type allows implicit return of undefined +} +function f23() { + // Error; because `undefined | number` becomes `number` without strictNullChecks. +} var C = /** @class */ (function () { function C() { } diff --git a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.symbols b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.symbols index f1bde79daa863..c7048ff46c778 100644 --- a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.symbols +++ b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.symbols @@ -46,14 +46,14 @@ function f7(): void { return null; } -function f8(): void { +function f8(): any { >f8 : Symbol(f8, Decl(functionsMissingReturnStatementsAndExpressions.ts, 30, 1)) // Fine since are typed any. return; } -function f9(): void { +function f9(): any { >f9 : Symbol(f9, Decl(functionsMissingReturnStatementsAndExpressions.ts, 35, 1)) // Fine since we are typed any and return undefined @@ -152,37 +152,49 @@ function f21(): number | string { // Not okay; union does not contain void or any } +function f22(): undefined { +>f22 : Symbol(f22, Decl(functionsMissingReturnStatementsAndExpressions.ts, 100, 1)) + + // Okay; return type allows implicit return of undefined +} + +function f23(): undefined | number { +>f23 : Symbol(f23, Decl(functionsMissingReturnStatementsAndExpressions.ts, 104, 1)) + + // Error; because `undefined | number` becomes `number` without strictNullChecks. +} + class C { ->C : Symbol(C, Decl(functionsMissingReturnStatementsAndExpressions.ts, 100, 1)) +>C : Symbol(C, Decl(functionsMissingReturnStatementsAndExpressions.ts, 108, 1)) public get m1() { ->m1 : Symbol(C.m1, Decl(functionsMissingReturnStatementsAndExpressions.ts, 102, 9)) +>m1 : Symbol(C.m1, Decl(functionsMissingReturnStatementsAndExpressions.ts, 110, 9)) // Errors; get accessors must return a value. } public get m2() { ->m2 : Symbol(C.m2, Decl(functionsMissingReturnStatementsAndExpressions.ts, 105, 5)) +>m2 : Symbol(C.m2, Decl(functionsMissingReturnStatementsAndExpressions.ts, 113, 5)) // Permissible; returns undefined. return; } public get m3() { ->m3 : Symbol(C.m3, Decl(functionsMissingReturnStatementsAndExpressions.ts, 110, 5)) +>m3 : Symbol(C.m3, Decl(functionsMissingReturnStatementsAndExpressions.ts, 118, 5)) return "Okay, because this is a return expression."; } public get m4() { ->m4 : Symbol(C.m4, Decl(functionsMissingReturnStatementsAndExpressions.ts, 114, 5)) +>m4 : Symbol(C.m4, Decl(functionsMissingReturnStatementsAndExpressions.ts, 122, 5)) // Fine since this consists of a single throw statement. throw null; } public get m5() { ->m5 : Symbol(C.m5, Decl(functionsMissingReturnStatementsAndExpressions.ts, 119, 5)) +>m5 : Symbol(C.m5, Decl(functionsMissingReturnStatementsAndExpressions.ts, 127, 5)) // Not fine, since we can *only* consist of a single throw statement // if no return statements are present but we are a get accessor. @@ -191,3 +203,4 @@ class C { >undefined : Symbol(undefined) } } + diff --git a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.types b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.types index 1fc53ae36ef3e..5e6b014bfa2d6 100644 --- a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.types +++ b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.types @@ -47,15 +47,15 @@ function f7(): void { return null; } -function f8(): void { ->f8 : () => void +function f8(): any { +>f8 : () => any // Fine since are typed any. return; } -function f9(): void { ->f9 : () => void +function f9(): any { +>f9 : () => any // Fine since we are typed any and return undefined return undefined; @@ -154,6 +154,18 @@ function f21(): number | string { // Not okay; union does not contain void or any } +function f22(): undefined { +>f22 : () => undefined + + // Okay; return type allows implicit return of undefined +} + +function f23(): undefined | number { +>f23 : () => undefined | number + + // Error; because `undefined | number` becomes `number` without strictNullChecks. +} + class C { >C : C @@ -196,3 +208,4 @@ class C { } > : any } + diff --git a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.errors.txt b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.errors.txt new file mode 100644 index 0000000000000..a570470cf2ea0 --- /dev/null +++ b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.errors.txt @@ -0,0 +1,25 @@ +tests/cases/compiler/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts(5,16): error TS2847: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. +tests/cases/compiler/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts(13,22): error TS2847: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. + + +==== tests/cases/compiler/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts (2 errors) ==== + function f1(): undefined | number { + // Okay; return type allows implicit return of undefined + } + + function f2(): number { + ~~~~~~ +!!! error TS2847: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. + // Error; return type does not include undefined + } + + async function f3(): Promise { + // Okay; return type allows implicit return of undefined + } + + async function f4(): Promise { + ~~~~~~~~~~~~~~~ +!!! error TS2847: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. + // Error; return type does not include undefined + } + \ No newline at end of file diff --git a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.js b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.js new file mode 100644 index 0000000000000..3ca9a8cc8353d --- /dev/null +++ b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.js @@ -0,0 +1,31 @@ +//// [functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts] +function f1(): undefined | number { + // Okay; return type allows implicit return of undefined +} + +function f2(): number { + // Error; return type does not include undefined +} + +async function f3(): Promise { + // Okay; return type allows implicit return of undefined +} + +async function f4(): Promise { + // Error; return type does not include undefined +} + + +//// [functionsMissingReturnStatementsAndExpressionsStrictNullChecks.js] +function f1() { + // Okay; return type allows implicit return of undefined +} +function f2() { + // Error; return type does not include undefined +} +async function f3() { + // Okay; return type allows implicit return of undefined +} +async function f4() { + // Error; return type does not include undefined +} diff --git a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.symbols b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.symbols new file mode 100644 index 0000000000000..befceb738b18a --- /dev/null +++ b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.symbols @@ -0,0 +1,27 @@ +=== tests/cases/compiler/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts === +function f1(): undefined | number { +>f1 : Symbol(f1, Decl(functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts, 0, 0)) + + // Okay; return type allows implicit return of undefined +} + +function f2(): number { +>f2 : Symbol(f2, Decl(functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts, 2, 1)) + + // Error; return type does not include undefined +} + +async function f3(): Promise { +>f3 : Symbol(f3, Decl(functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts, 6, 1)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) + + // Okay; return type allows implicit return of undefined +} + +async function f4(): Promise { +>f4 : Symbol(f4, Decl(functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts, 10, 1)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) + + // Error; return type does not include undefined +} + diff --git a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.types b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.types new file mode 100644 index 0000000000000..beb7ae82be089 --- /dev/null +++ b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.types @@ -0,0 +1,25 @@ +=== tests/cases/compiler/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts === +function f1(): undefined | number { +>f1 : () => undefined | number + + // Okay; return type allows implicit return of undefined +} + +function f2(): number { +>f2 : () => number + + // Error; return type does not include undefined +} + +async function f3(): Promise { +>f3 : () => Promise + + // Okay; return type allows implicit return of undefined +} + +async function f4(): Promise { +>f4 : () => Promise + + // Error; return type does not include undefined +} + diff --git a/tests/baselines/reference/jsdocFunction_missingReturn.errors.txt b/tests/baselines/reference/jsdocFunction_missingReturn.errors.txt index 646e03fcd6f57..8e102d797ec7c 100644 --- a/tests/baselines/reference/jsdocFunction_missingReturn.errors.txt +++ b/tests/baselines/reference/jsdocFunction_missingReturn.errors.txt @@ -1,9 +1,9 @@ -/a.js(1,24): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. +/a.js(1,24): error TS2847: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. ==== /a.js (1 errors) ==== /** @type {function(): number} */ ~~~~~~ -!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. +!!! error TS2847: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. function f() {} \ No newline at end of file diff --git a/tests/baselines/reference/parseInvalidNonNullableTypes.errors.txt b/tests/baselines/reference/parseInvalidNonNullableTypes.errors.txt index a5b8dbef915bd..378419d288544 100644 --- a/tests/baselines/reference/parseInvalidNonNullableTypes.errors.txt +++ b/tests/baselines/reference/parseInvalidNonNullableTypes.errors.txt @@ -4,9 +4,9 @@ tests/cases/compiler/parseInvalidNonNullableTypes.ts(9,16): error TS17019: '!' a tests/cases/compiler/parseInvalidNonNullableTypes.ts(10,16): error TS17019: '!' at the end of a type is not valid TypeScript syntax. Did you mean to write 'number'? tests/cases/compiler/parseInvalidNonNullableTypes.ts(12,16): error TS17020: '!' at the start of a type is not valid TypeScript syntax. Did you mean to write 'string'? tests/cases/compiler/parseInvalidNonNullableTypes.ts(13,16): error TS17020: '!' at the start of a type is not valid TypeScript syntax. Did you mean to write 'number'? -tests/cases/compiler/parseInvalidNonNullableTypes.ts(15,16): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. +tests/cases/compiler/parseInvalidNonNullableTypes.ts(15,16): error TS2847: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. tests/cases/compiler/parseInvalidNonNullableTypes.ts(15,16): error TS17019: '!' at the end of a type is not valid TypeScript syntax. Did you mean to write 'string'? -tests/cases/compiler/parseInvalidNonNullableTypes.ts(16,16): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. +tests/cases/compiler/parseInvalidNonNullableTypes.ts(16,16): error TS2847: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. tests/cases/compiler/parseInvalidNonNullableTypes.ts(16,16): error TS17020: '!' at the start of a type is not valid TypeScript syntax. Did you mean to write 'string'? tests/cases/compiler/parseInvalidNonNullableTypes.ts(18,16): error TS17019: '!' at the end of a type is not valid TypeScript syntax. Did you mean to write 'any'? tests/cases/compiler/parseInvalidNonNullableTypes.ts(19,10): error TS17019: '!' at the end of a type is not valid TypeScript syntax. Did you mean to write 'number'? @@ -43,12 +43,12 @@ tests/cases/compiler/parseInvalidNonNullableTypes.ts(22,10): error TS17020: '!' function f7(): string! {} ~~~~~~~ -!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. +!!! error TS2847: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. ~~~~~~~ !!! error TS17019: '!' at the end of a type is not valid TypeScript syntax. Did you mean to write 'string'? function f8(): !string {} ~~~~~~~ -!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. +!!! error TS2847: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. ~~~~~~~ !!! error TS17020: '!' at the start of a type is not valid TypeScript syntax. Did you mean to write 'string'? diff --git a/tests/baselines/reference/unknownType1.errors.txt b/tests/baselines/reference/unknownType1.errors.txt index 2a46fbeac4a59..32034c8e2b9d9 100644 --- a/tests/baselines/reference/unknownType1.errors.txt +++ b/tests/baselines/reference/unknownType1.errors.txt @@ -20,7 +20,7 @@ tests/cases/conformance/types/unknown/unknownType1.ts(128,5): error TS2322: Type tests/cases/conformance/types/unknown/unknownType1.ts(129,5): error TS2322: Type 'number' is not assignable to type '{ [x: string]: unknown; }'. tests/cases/conformance/types/unknown/unknownType1.ts(143,29): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/unknown/unknownType1.ts(144,29): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/unknown/unknownType1.ts(150,17): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. +tests/cases/conformance/types/unknown/unknownType1.ts(150,17): error TS2847: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. tests/cases/conformance/types/unknown/unknownType1.ts(156,14): error TS2700: Rest types may only be created from object types. tests/cases/conformance/types/unknown/unknownType1.ts(162,5): error TS2564: Property 'a' has no initializer and is not definitely assigned in the constructor. tests/cases/conformance/types/unknown/unknownType1.ts(170,9): error TS2322: Type 'T' is not assignable to type '{}'. @@ -223,7 +223,7 @@ tests/cases/conformance/types/unknown/unknownType1.ts(181,5): error TS2322: Type function f27(): unknown { ~~~~~~~ -!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. +!!! error TS2847: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. } // Rest type cannot be created from unknown diff --git a/tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts b/tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts index 582940038c5e5..cf5eb31ecad58 100644 --- a/tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts +++ b/tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts @@ -34,12 +34,12 @@ function f7(): void { return null; } -function f8(): void { +function f8(): any { // Fine since are typed any. return; } -function f9(): void { +function f9(): any { // Fine since we are typed any and return undefined return undefined; } @@ -104,6 +104,14 @@ function f21(): number | string { // Not okay; union does not contain void or any } +function f22(): undefined { + // Okay; return type allows implicit return of undefined +} + +function f23(): undefined | number { + // Error; because `undefined | number` becomes `number` without strictNullChecks. +} + class C { public get m1() { // Errors; get accessors must return a value. @@ -129,4 +137,4 @@ class C { throw null; throw undefined. } -} \ No newline at end of file +} diff --git a/tests/cases/compiler/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts b/tests/cases/compiler/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts new file mode 100644 index 0000000000000..89d3d5866221a --- /dev/null +++ b/tests/cases/compiler/functionsMissingReturnStatementsAndExpressionsStrictNullChecks.ts @@ -0,0 +1,19 @@ +// @strictNullChecks: true + +// @target: es2018 + +function f1(): undefined | number { + // Okay; return type allows implicit return of undefined +} + +function f2(): number { + // Error; return type does not include undefined +} + +async function f3(): Promise { + // Okay; return type allows implicit return of undefined +} + +async function f4(): Promise { + // Error; return type does not include undefined +} diff --git a/tests/cases/fourslash/codeFixCorrectReturnValue6.ts b/tests/cases/fourslash/codeFixCorrectReturnValue6.ts index 693145f8c61b8..a7dbffae98cf3 100644 --- a/tests/cases/fourslash/codeFixCorrectReturnValue6.ts +++ b/tests/cases/fourslash/codeFixCorrectReturnValue6.ts @@ -4,6 +4,4 @@ //// undefined //// } -verify.codeFixAvailable([ - { description: 'Add a return statement' }, -]); +verify.not.codeFixAvailable();