In TypeScript 2, you can use the undefined type to check for undefined values.
If you declare a variable as:
let uemail : string | undefined;
Then you can check if the variable uemail is undefined like this:
if(uemail === undefined)
{
}
Answer from ashish on Stack OverflowIn TypeScript 2, you can use the undefined type to check for undefined values.
If you declare a variable as:
let uemail : string | undefined;
Then you can check if the variable uemail is undefined like this:
if(uemail === undefined)
{
}
From Typescript 3.7 on, you can also use nullish coalescing:
let x = foo ?? bar();
Which is the equivalent for checking for null or undefined:
let x = (foo !== null && foo !== undefined) ?
foo :
bar();
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#nullish-coalescing
While not exactly the same, you could write your code as:
var uemail = localStorage.getItem("useremail") ?? alert('Undefined');
Using a juggling-check, you can test both null and undefined in one hit:
if (x == null) {
If you use a strict-check, it will only be true for values set to null and won't evaluate as true for undefined variables:
if (x === null) {
You can try this with various values using this example:
var a: number;
var b: number = null;
function check(x, name) {
if (x == null) {
console.log(name + ' == null');
}
if (x === null) {
console.log(name + ' === null');
}
if (typeof x === 'undefined') {
console.log(name + ' is undefined');
}
}
check(a, 'a');
check(b, 'b');
Output
"a == null"
"a is undefined"
"b == null"
"b === null"
if( value ) {
}
will evaluate to true if value is not:
nullundefinedNaN- empty string
'' 0false
typescript includes javascript rules.
Let me try to explain you what is typescript thinks about your code and how it acts:
class TestClass {
// this is the worst possible getter for a typescript compiler
// the random nature of the getter deceives both the compiler and the developer
get person(): Person | undefined {
if (Math.random() > 0.5) return undefined
return { name: 'Bob', age: 35 }
}
get test() {
if (!this.person) return undefined
// In here TS compiler thinks that accessing this.person.name
// is safe because the above line has a guard for it.
// But it will throw runtime errors by %50 chance
// Note that TS doesn't aware of its randomness here
const name = this.person.name //
// If we describe this line we call it a local arrow function definition
// Since it's a definition and also there is no nullability guard in it TS is right about complaining here
// Since it's a definition it is not deterministic where it
// will be called in the code, and the compiler can't be sure whether it is null or not.
const processPerson = () => this.person.name // Object is possibly 'undefined'.(2532)
return processPerson()
}
}
The other answers have already good practices to avoid the error and possible runtime issues.
The problem is that your test calls the getter twice, and since the getter randomly returns either undefined or a value, the two lines don't get the same value.
Looks like the first call to the getter gets a value, while the second call gets undefined.
To fix this, call the getter once at the beginning of the test method, and assign the result to a local variable. Then test the local variable instead of calling the getter, like this
test() {
const subject = this.person;
if (!subject) return undefined
const name = subject.name
const processPerson = () => subject
return processPerson()
}
You can make throwIfUndefined an assertion function to narrow the type of its argument to something that does not include undefined in its domain. An assertion function has an assertion type predicate of the form asserts x is Y as its return type, where x is the name of one of the function's parameters, and Y is the subtype of typeof X that we narrow x to assuming the function returns successfully. Assertion functions cannot return a defined value; they are basically void-returning functions.
For throwIfUndefined, here's the normal way to do it, as a function statement:
function throwIfUndefined<T>(x: T | undefined): asserts x is T {
if (typeof x === "undefined") throw new Error("OH NOEZ");
}
You can also write it as an arrow function, although you need to explicitly annotate the variable with its type for the control flow analysis to happen correctly:
const throwIfUndefined: <T, >(x: T | undefined) => asserts x is T = x => {
if (typeof x === "undefined") throw new Error("OH NOEZ");
}
Either way should work:
const Index = ({ params }: { params: { myVar: string | undefined } }) => {
const { myVar } = params // myVar: string | undefined
// myVar.toUpperCase // <-- error, Object is possibly 'undefined'
throwIfUndefined(myVar);
return myVar.toUpperCase() // no error now
}
try {
console.log(Index({
params: {
myVar: Math.random() < 0.5 ? "hello" : undefined
}
})) // 50% "HELLO"
} catch (e) {
console.log(e); // 50% "OH NOEZ"
}
Playground link to code
You could skip definedOrRedirect and use an explicit check:
export const loader: LoaderFunction = async ({ params }) => {
const { myVar } = params; // myVar: string | undefined
if (myVar == undefined) {
return redirect("/");
}
return fetchSomething(myVar); // myVar: string
}
Or you could keep definedOrRedirect and declare it with an assertion as jcalz suggests:
function definedOrRedirect(variable, path): asserts variable is string
{
if (variable == undefined) {
return redirect(path);
}
}
export const loader: LoaderFunction = async ({ params }) => {
const { myVar } = params; // myVar: string | undefined
definedOrRedirect(myVar, "/");
return fetchSomething(myVar); // myVar: string
}
Update: For simplicity, I replicated the original error with simpler code.
Update 2: I got around this by using a type guard for T. Thank u/ritajalilip for the suggestion. I still think Typescript should handle this better though.
As you can see on the screenshot, inside the if statement I'm asserting that x is not undefined. However Typescript is failing to acknowledge and still thinks that x can be undefined.
Any idea of what's going on?
if(!point && !optionB)
This IF block would be skipped if either point or optionB is undefined.
Let's say optionB is undefined..------------------(1)
The first block is skipped, as per your condition.
obviously, TS will point out to you that optionB is possibly undefined in the second block (assumption (1))
Now Lets say point is undefined....................(2)
The first block is skipped, as per your condition.
TS will again point to you that point is possibly undefined in the second block (assumption (2)).
This is why you see both linting errors.
If optionB is defined you will never enter your if.
That's why you need to explicit test the value of point.
The logical nullish assignment (x ??= y) operator only assigns if x is nullish (null or undefined).
x ??= default_value
TypeScript can tell that x is definitely not defined, because it is a block-scoped variable and you can see the whole block.
If you know better than the compiler, you can separate the lines:
const def_val = 'default';
let x: string;
x = (typeof x === 'undefined') ? def_val : x;
But you might want to consider how the block scoped variable could possibly be undefined in your case (perhaps your code is not quite as simple as the example in your question).
The common use case would be more like:
const def_val = 'default';
function work(y: string) {
let x = (typeof y === 'undefined') ? def_val : y;
}
You can also add more strict compiler options to make it less likely the value will be undefined in many cases.
Shorthand
There is also a shorthand falsey-coalesce that may be useful:
const def_val = 'default';
function work(y: string) {
let x = y || def_val;
}
This will replace undefined, null, 0 (zero) or '' with the default.
This code do not work at all, but not sure why.
type IsUndefined<T> = T extends undefined ? 1 : 0;
For example:
type IsTypeUndefined = IsUndefined<number | undefined>; // This returns: 1 | 0
Is there a way for check if a type is undefined in a conditional?