TypeScript Version: 2.2.1
Code
function foo(bar: string | undefined = '') {
bar = undefined;
// ^ Type 'undefined' is not assignable to type 'string'.
}
Possibly related to #13826.
This is related to #14406
you can work around it by doing function foo(bar = <string | undefined>'') { ...
@krisselden Nice try but that will make the variable string | undefined when entering the function.
This is really a design limitation in the existing system. See https://github.com/Microsoft/TypeScript/pull/12033 for more details on why and how it was implemented.
The crux here is outside the function the type is string | undefined. in side the function, since there is a default, the undefined is stripped out of the type leaving you with only string. This means that the type annotation is not really changing any thing, it is still string | undefined for the caller, and string within the function body.
@mhegazy But can't we just do something similar with something like:
let p: string | undefined = '';
// here `p` has type `string`
p = undefined; // no error
I understand that sometimes if we write (p = '') in parameter list we would want the type of p to be string, but maybe we should treat p: string | undefined = '' differently as it explicitly specifies the type of p.
Yes, I think there is a difference between "I said this could be undefined for callers" vs "this can always be undefined". It's not clear what the limitations are from the linked discussion. @sandersn
We have talked in the past about distinguishing yet another "empty" value called missing, which would allow us to distinguish between things like f() and f(undefined) or {} and { x: undefined }. That's the missing piece here. It would allow the compiler to distinguish these cases:
function f(x: string = '') {
x.length // ok
x = undefined // error!
}
function g(y: string | undefined = '') {
y.length // ok, undefined was removed by narrowing
y = undefined // ok
}
f(undefined) // error!
g(undefined) // ok!
By letting the assigned type of x: string | missing and y: string | undefined | missing. This additional type would let the compiler disallow the call f(undefined) but allow g(undefined). And inside the function the default initialiser would remove both undefined and missing, so the type of both would be string. However, in g, the assigned type of y would still allow assignment of undefined.
If we added missingType, default initialisers and ? would add it; I'm not sure if there would be syntax in the language for it. There probably wouldn't be any values at all of type missing because it signifies the absence of values.
We did not add this feature for a few reasons.
? vs | undefined in object literals [1] is a lot less clear. This change would break code and it's not clear that the object literal break is a desired one.The mixture of complexity, limited applicability and possibility of unwanted breakage sank this feature. We might re-visit this in the future, but I don't think our decision will change.
[1] To be consistent object literal ? should add missing instead of undefined as well:
type A = {
a?: number,
other1: number | undefined,
other2?: number | undefined,
other3: number
}
let o: A = {
a: undefined // error! Previously ok
// missing other1: error before and after
// missing other2: ok
other2: undefined // also ok before and after
// missing other3: error before and after
As the error says, localStorage.getItem() can return either a string or null. JSON.parse() requires a string, so you should test the result of localStorage.getItem() before you try to use it.
For example:
this.currentUser = JSON.parse(localStorage.getItem('currentUser') || '{}');
or perhaps:
const userJson = localStorage.getItem('currentUser');
this.currentUser = userJson !== null ? JSON.parse(userJson) : new User();
Most helpful comment
We have talked in the past about distinguishing yet another "empty" value called missing, which would allow us to distinguish between things like
f()andf(undefined)or{}and{ x: undefined }. That's the missing piece here. It would allow the compiler to distinguish these cases:By letting the assigned type of
x: string | missingandy: string | undefined | missing. This additional type would let the compiler disallow the callf(undefined)but allowg(undefined). And inside the function the default initialiser would remove bothundefinedandmissing, so the type of both would bestring. However, ing, the assigned type ofywould still allow assignment ofundefined.If we added
missingType, default initialisers and?would add it; I'm not sure if there would be syntax in the language for it. There probably wouldn't be any values at all of typemissingbecause it signifies the absence of values.We did not add this feature for a few reasons.
?vs| undefinedin object literals [1] is a lot less clear. This change would break code and it's not clear that the object literal break is a desired one.The mixture of complexity, limited applicability and possibility of unwanted breakage sank this feature. We might re-visit this in the future, but I don't think our decision will change.
[1] To be consistent object literal
?should addmissinginstead ofundefinedas well: