All the rules about widening of literal types which concern this question were written down in PR/#10676.
Let's look at the first expression:
const message = Math.random() > 0.5 ? "hello, can you here me" : null;
The first rule applicable to this statement is the following:
The type of a string or numeric literal occurring in an expression is a widening literal type.
The expression itself is inferred to be a "widening literal type" which is a literal type that can be widened by the compiler as appropriate.
But is it appropriate in our example? The PR states that
The type inferred for a const variable or readonly property without a type annotation is the type of the initializer as-is.
As message
is a const
variable, the type of the widened literal type of the expression is not widened and stays "hello, can you here me" | null
.
The compiler would find widening appropriate for a let
variable.
let message = Math.random() > 0.5 ? "hello, can you here me" : null;
// ^? message: string | null
When it comes to inferred function return types, the PR states that
In a function with no return type annotation, if the inferred return type is a literal type (but not a literal union type) and the function does not have a contextual type with a return type that includes literal types, the return type is widened to its widened literal type
Let's look again at the function:
const getName = () => "John Gump";
We can see that indeed the functions return type would be a literal type "John Gump"
. This is not a union and there is also no contextual type which concludes to the return type being widened to its widened literal type string
.
getName
? Right now, its type is a function returning a string. – Albite