TypeScript Version: 2.1.0-dev.20160819
Code
// Type representing the falsy values
type Falsy = null | undefined | false | 0 | ''; // No NaN type
function assert(value: Falsy, message: string): never;
function assert<T>(value: T, message: string): T;
function assert<T>(value: Falsy | T, message: string): never | T {
if (!value) throw new Error(`AssertError: ${message}`);
return value;
}
function foo(bar: number): string {
// Unimportant
if (bar === 0) return 'off';
if (bar > 1) return 'on';
assert(false, 'Invalid value for bar'); // because of 'false' argument, this will have return type 'never'
// Error: Function lacks ending return statement and return type does not include 'undefined'
}
Expected behavior:
I would expect if the type system knows that assert(false, '') never returns, it doesn't require a return statement after assert.
Actual behavior:
Error on foo function:
Function lacks ending return statement and return type does not include 'undefined'
Somewhat related: #8655
A simple fix is:
function foo(bar: number): string | undefined {
if (bar = 0) return 'off';
if (bar > 1) return 'on';
assert(false, 'Invalid value for bar');
}
It does appear to essentially be a dupe of #8655 in the sense that this is valid:
function foo(bar: number): string {
// Unimportant
if (bar = 0) return 'off';
if (bar > 1) return 'on';
throw new Error('Invalid value for bar');
}
On the other hand, never says that there will not be a return, it does not contract to say that it will throw, which is what the code analysis is trying to determine.
@kitsonk
The problem is not related to the Error thrown. If the assert function is a function with an infinite loop:
function assert(): never {
while (true) {
}
}
the problem would be the same.
See: https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#the-never-type
The suggested solution adds | undefined to the signature of the function and requires unneeded null checks after calling the foo() function.
To satisfy the compiler, I think I'm better of with adding just a return statement:
function foo(bar: number): string {
if (bar === 0) return 'off';
if (bar > 1) return 'on';
assert(false, 'Invalid value for bar'); // because of 'false' argument, this will have return type 'never'
return undefined!; // never reached
}
I totally understand what the never type is. It is a bottom type, but it does not affect the flow control of the code, for some very important reasons. In fact, the "what is new" expresses the behaviour you are experiencing is by design:
// Function returning never must have unreachable end point
function error(message: string): never {
throw new Error(message);
}
// Inferred return type is number
function move1(direction: "up" | "down") {
switch (direction) {
case "up":
return 1;
case "down":
return -1;
}
return error("Should never get here");
}
// Inferred return type is number
function move2(direction: "up" | "down") {
return direction === "up" ? 1 :
direction === "down" ? -1 :
error("Should never get here");
}
// Inferred return type is T
function check<T>(x: T | undefined) {
return x || error("Undefined value");
}
And to quote:
Because
neveris a subtype of every type, it is always omitted from union types and it is ignored in function return type inference as long as there are other types being returned.
The 'problem' I have is when there is code after a function that never returns.
The compiler warns that there is a code path that doesn't return a value.
I think the compiler warning is not needed there, because that code path will/can never be reached (at least if the function type signature doesn't lie)
The intended fix is
return assert(false, 'Invalid value for bar');
There are technical reasons why we can't figure this out correctly today but I'm not remembering exactly why right now. I'll follow up.
Thanx
How can I resolve these errors here?
[ts] Function lacks ending return statement and return type does not include 'undefined'.
[ts] Parameter 'conversation' implicitly has an 'any' type.
[ts] Not all code paths return a value.
By asking "how to use TypeScript" questions on StackOverflow or Gitter?
@kitsonk 💯
Most helpful comment
The intended fix is
There are technical reasons why we can't figure this out correctly today but I'm not remembering exactly why right now. I'll follow up.