mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-31 18:10:56 -05:00
Explicit undefined return type checked similar to explicit void return type (#53607)
This commit is contained in:
@@ -35426,10 +35426,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
: neverType; // Normal function
|
||||
}
|
||||
if (types.length === 0) {
|
||||
// For an async function, the return type will not be void, but rather a Promise for void.
|
||||
return functionFlags & FunctionFlags.Async
|
||||
? createPromiseReturnType(func, voidType) // Async function
|
||||
: voidType; // Normal function
|
||||
// For an async function, the return type will not be void/undefined, but rather a Promise for void/undefined.
|
||||
const contextualReturnType = getContextualReturnType(func, /*contextFlags*/ undefined);
|
||||
const returnType = contextualReturnType && (unwrapReturnType(contextualReturnType, functionFlags) || voidType).flags & TypeFlags.Undefined ? undefinedType : voidType;
|
||||
return functionFlags & FunctionFlags.Async ? createPromiseReturnType(func, returnType) : // Async function
|
||||
returnType; // Normal function
|
||||
}
|
||||
|
||||
// Return a union of the return expression types.
|
||||
@@ -35665,8 +35666,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const functionFlags = getFunctionFlags(func);
|
||||
const type = returnType && unwrapReturnType(returnType, functionFlags);
|
||||
|
||||
// Functions with an explicitly specified 'undefined, 'void', 'any' or 'unknown' return type don't need any return expressions.
|
||||
if (type && maybeTypeOfKind(type, TypeFlags.Undefined | TypeFlags.Void | TypeFlags.Any | TypeFlags.Unknown)) {
|
||||
// Functions with an explicitly specified return type that includes `void` or is exactly `any` or `undefined` don't
|
||||
// need any return statements.
|
||||
if (type && (maybeTypeOfKind(type, TypeFlags.Void) || type.flags & (TypeFlags.Any | TypeFlags.Undefined))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -35685,14 +35687,9 @@ 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.
|
||||
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);
|
||||
}
|
||||
error(errorNode, Diagnostics.A_function_whose_declared_type_is_neither_undefined_void_nor_any_must_return_a_value);
|
||||
}
|
||||
else if (type && strictNullChecks) {
|
||||
else if (type && strictNullChecks && !isTypeAssignableTo(undefinedType, type)) {
|
||||
error(errorNode, Diagnostics.Function_lacks_ending_return_statement_and_return_type_does_not_include_undefined);
|
||||
}
|
||||
else if (compilerOptions.noImplicitReturns) {
|
||||
@@ -35704,7 +35701,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return;
|
||||
}
|
||||
const inferredReturnType = getReturnTypeOfSignature(getSignatureFromDeclaration(func));
|
||||
if (isUnwrappedReturnTypeVoidOrAny(func, inferredReturnType)) {
|
||||
if (isUnwrappedReturnTypeUndefinedVoidOrAny(func, inferredReturnType)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -42182,9 +42179,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return isAsync ? getAwaitedTypeNoAlias(returnType) || errorType : returnType;
|
||||
}
|
||||
|
||||
function isUnwrappedReturnTypeVoidOrAny(func: SignatureDeclaration, returnType: Type): boolean {
|
||||
const unwrappedReturnType = unwrapReturnType(returnType, getFunctionFlags(func));
|
||||
return !!unwrappedReturnType && maybeTypeOfKind(unwrappedReturnType, TypeFlags.Void | TypeFlags.AnyOrUnknown);
|
||||
function isUnwrappedReturnTypeUndefinedVoidOrAny(func: SignatureDeclaration, returnType: Type): boolean {
|
||||
const type = unwrapReturnType(returnType, getFunctionFlags(func));
|
||||
return !!(type && (maybeTypeOfKind(type, TypeFlags.Void) || type.flags & (TypeFlags.Any | TypeFlags.Undefined)));
|
||||
}
|
||||
|
||||
function checkReturnStatement(node: ReturnStatement) {
|
||||
@@ -42232,7 +42229,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (container.kind !== SyntaxKind.Constructor && compilerOptions.noImplicitReturns && !isUnwrappedReturnTypeVoidOrAny(container, returnType)) {
|
||||
else if (container.kind !== SyntaxKind.Constructor && compilerOptions.noImplicitReturns && !isUnwrappedReturnTypeUndefinedVoidOrAny(container, returnType)) {
|
||||
// The function has a return type, but the return statement doesn't have an expression.
|
||||
error(node, Diagnostics.Not_all_code_paths_return_a_value);
|
||||
}
|
||||
|
||||
@@ -1880,7 +1880,7 @@
|
||||
"category": "Error",
|
||||
"code": 2354
|
||||
},
|
||||
"A function whose declared type is neither 'void' nor 'any' must return a value.": {
|
||||
"A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.": {
|
||||
"category": "Error",
|
||||
"code": 2355
|
||||
},
|
||||
@@ -3615,10 +3615,6 @@
|
||||
"category": "Error",
|
||||
"code": 2846
|
||||
},
|
||||
"A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.": {
|
||||
"category": "Error",
|
||||
"code": 2847
|
||||
},
|
||||
"The right-hand side of an 'instanceof' expression must not be an instantiation expression.": {
|
||||
"category": "Error",
|
||||
"code": 2848
|
||||
|
||||
@@ -51,7 +51,6 @@ const fixIdAddReturnStatement = "fixAddReturnStatement";
|
||||
const fixRemoveBracesFromArrowFunctionBody = "fixRemoveBracesFromArrowFunctionBody";
|
||||
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,7 +213,6 @@ 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);
|
||||
|
||||
Reference in New Issue
Block a user