diff --git a/doc/TypeScript Language Specification.docx b/doc/TypeScript Language Specification.docx index 78c86917551..4b8d3998f90 100644 Binary files a/doc/TypeScript Language Specification.docx and b/doc/TypeScript Language Specification.docx differ diff --git a/doc/spec.md b/doc/spec.md index 30de2c5a6b6..fa69d321056 100644 --- a/doc/spec.md +++ b/doc/spec.md @@ -3885,7 +3885,7 @@ function g(x: number) { the inferred return type for 'f' and 'g' is Any because the functions reference themselves through a cycle with no return type annotations. Adding an explicit return type 'number' to either breaks the cycle and causes the return type 'number' to be inferred for the other. -An explicitly typed function whose return type isn't the Void or the Any type must have at least one return statement somewhere in its body. An exception to this rule is if the function implementation consists of a single 'throw' statement. +An explicitly typed function whose return type isn't the Void type, the Any type, or a union type containing the Void or Any type as a constituent must have at least one return statement somewhere in its body. An exception to this rule is if the function implementation consists of a single 'throw' statement. The type of 'this' in a function implementation is the Any type. diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4ea8c71e054..645b3835b93 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10404,7 +10404,8 @@ namespace ts { /* *TypeScript Specification 1.0 (6.3) - July 2014 - * An explicitly typed function whose return type isn't the Void or the Any type + * An explicitly typed function whose return type isn't the Void type, + * the Any type, or a union type containing the Void or Any type as a constituent * must have at least one return statement somewhere in its body. * An exception to this rule is if the function implementation consists of a single 'throw' statement. * @param returnType - return type of the function, can be undefined if return type is not explicitly specified @@ -10415,7 +10416,7 @@ namespace ts { } // Functions with with an explicitly specified 'void' or 'any' return type don't need any return expressions. - if (returnType === voidType || isTypeAny(returnType)) { + if (returnType === voidType || isTypeAny(returnType) || (returnType && (returnType.flags & TypeFlags.Union) && someConstituentTypeHasKind(returnType, TypeFlags.Any | TypeFlags.Void))) { return; } diff --git a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.errors.txt b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.errors.txt index 58ffd051d4d..1ccc296b75b 100644 --- a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.errors.txt +++ b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.errors.txt @@ -1,9 +1,10 @@ tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(3,16): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. -tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(95,16): error TS2378: A 'get' accessor must return a value. -tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(118,5): error TS1003: Identifier expected. +tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(101,17): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. +tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(106,16): error TS2378: A 'get' accessor must return a value. +tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(129,5): error TS1003: Identifier expected. -==== tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts (3 errors) ==== +==== tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts (4 errors) ==== function f1(): string { @@ -98,6 +99,19 @@ tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts(118,5): e return "Okay, not type annotated."; } + function f19(): void | number { + // Okay; function return type is union containing void + } + + function f20(): any | number { + // Okay; function return type is union containing any + } + + function f21(): number | string { + ~~~~~~~~~~~~~~~ +!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. + // Not okay; union does not contain void or any + } class C { public get m1() { diff --git a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.js b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.js index 4dfe851683a..17468722e20 100644 --- a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.js +++ b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.js @@ -91,6 +91,17 @@ function f18() { return "Okay, not type annotated."; } +function f19(): void | number { + // Okay; function return type is union containing void +} + +function f20(): any | number { + // Okay; function return type is union containing any +} + +function f21(): number | string { + // Not okay; union does not contain void or any +} class C { public get m1() { @@ -191,6 +202,15 @@ function f17() { function f18() { return "Okay, not type annotated."; } +function f19() { + // Okay; function return type is union containing void +} +function f20() { + // Okay; function return type is union containing any +} +function f21() { + // Not okay; union does not contain void or any +} var C = (function () { function C() { } diff --git a/tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts b/tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts index fde615af41d..582940038c5 100644 --- a/tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts +++ b/tests/cases/compiler/functionsMissingReturnStatementsAndExpressions.ts @@ -92,6 +92,17 @@ function f18() { return "Okay, not type annotated."; } +function f19(): void | number { + // Okay; function return type is union containing void +} + +function f20(): any | number { + // Okay; function return type is union containing any +} + +function f21(): number | string { + // Not okay; union does not contain void or any +} class C { public get m1() {