Argument of type 'string | undefined' is not assignable to parameter of type 'string' - TypeScript error - javascript

TS error "Object is undefined"
Trying to access "userid" from my headers.
It keeps throwing the error "Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
Type 'undefined' is not assignable to type 'string'."
When I have already defined userid as string or undefined why does this error pop up??
Any idea anyone????
Update:
Adding a check before accessing apiGateway event
if (apiGateway.event !== undefined) {
const { userid } = req.apiGateway.event.headers;
} else {
throw new badRequestException()
}
return......

Judging by your definition of MyRequest:
apiGateway can be undefined
event cannot be undefined
headers cannot be undefined
userid can be undefined
So right off the bat, writing req.apiGateway.event.headers will fail, because if apiGateway is undefined, then accessing .event on it will crash. So Typescript does not allow that.
There are three ways around this:
Explicitly check against it. Something like if (req.apiGateway === undefined) { throw new badRequestException(); }
If you're certain that it can't be undefined, you can force TypeScript to accept it. Write req.apiGateway!.event. Mind you, if apiGateway does happen to be undefined at runtime, you'll get an exception. So only use this if you are absolutely 100% sure that it cannot under any circumstance be undefined.
Accept that it can be undefined and coerce everything else to undefined as well. Write req.apiGateway?.event - in this case .event will also be considered as undefined-able. If req.apiGateway happens to be undefined in runtime, then req.apiGateway?.event will also be undefined. And so on and so forth. This means that you'll also have to add ?. to the rest of the line: req.apiGateway?.event?.headers. And the result of the whole expression is ALSO undefined-able, so you'll probably need to use more undefined-checks later.
Now, for your second problem. Currently your userid local variable has the type string|undefined. That us because req.apiGateway.event.headers.userid is string|undefined. This means that at runtime it can be either a string, or undefined. However the method updateNotification() expects a simple string as its parameter. It cannot deal with undefined values. If you were to pass it undefined, who knows what would happen (probably an exception). Therefore Typescript does not allow this. And, again, you can use the above methods for dealing with it.

always when you got this error it's good to just check if variable has some value:
if(!variable) return
// continue
after this if type of variable will be string instead of string | undefined

Related

How to get "property missing" error messages with empty (and thus unsealed) objects

So, I have an API that takes an options object, something like this:
type Options = { pos: number };
function doTheThing(options: Options) {
}
Now, if I call this with any of the below, I get a nice error message:
doTheThing(); // requires another argument.
doTheThing({ something: 20 }); // missing property "pos"
Great. But if I pass an empty object, Flow will consider this "unsealed" and thus have no issue with it:
doTheThing({ }); // No error, would like it to say "pos" missing instead.
So, I tried making it exact:
type Options = {| pos: number |};
Now, I get an error, but it's not very nice:
doTheThing({ }); // Cannot call `doTheThing` with object literal bound to `options` because inexact object literal [1] is incompatible with exact `Options` [2].
But I just want it to say "pos" is missing. The above is more complicated and just forces you to have to read the definition of Options in order to know what it takes. I want it to offer the actual missing property to you. Which it will do, as soon as I put any random thing in there:
doTheThing({ x: 10 }); // Cannot call `doTheThing` with object literal bound to `options` because property `pos` is missing in object literal [1] but exists in `Options`
Is there any way to get it to give me that error message on {}, instead of the less useful message? Ideally through some sort of extra annotation on the type and not some global flow configuration that like turns off unsealed objects or something.

Is it possible to let the interpreter know my method checks for undefined/null in TypeScript

For example I have a method isEmpty that checks if anything is empty, null, or undefined and returns true if so.
However in TypeScript it doesn't let the interpreter know that this is the case and I get a red underline in my IDE (WebStorm)
Example code
let str: string | undefined = undefined
if (!isEmpty(str)) {
doSomeWorkFunction(str) // this line is shows the error 'string | undefined is not assignable to type string
}
However if the code is
let str: string | undefined = undefined
if (str) {
doSomeWorkFunction(str) // no error because the interpreter knows I checked the value
}
The fix I would like to avoid is
let str: string | undefined = undefined
if (!isEmpty(str)){
// #ts-ignore
doSomeWorkFunction(str) // no error since ts is now ignoring this error
}
How might I go about still keeping the TypeScript strict null checks in place without having to ignore issues like this.
TypeScript has a feature called "type guards" that helps in this situation: https://www.typescriptlang.org/docs/handbook/advanced-types.html. Specifically, it lets you tell the compiler that the return type is not just a boolean, but a boolean that means something specific about the types of the inputs. For example, you can convert a function like this
function isDefinedString(input: string | undefined): boolean
into a function like this:
function isDefinedString(input: string | undefined): input is string
The return type is still a boolean, but now the compiler will assume that the input is specifically a string and not any other type allowed by the argument declaration (in this case undefined).
Try using this signature on your existing isEmpty function declaration. Although not required to make it work, because you are adding this additional context to the function signature I'd recommend changing the name of isEmpty to reflect its dual purpose of checking emptiness and whether the variable is defined.
Edit:
One caveat to returning type information is that returning false will make the compiler assume that the object is not that type. In the above example, if isDefinedString returns false then the compiler will assume that it is not a string. This runs into problems with any or generic parameters, because returning false effectively tells the compiler that there is no type (or in the compiler's words, there is "never" a type) that satisfies your criteria. While this doesn't result in an error directly, the fact that the compiler has no type that works with your object means you can't do anything meaningful with the object in the if/else branch triggered by your type guard returning false. As such, if you are using a broad type such as any or a generic, you will want to limit what your type guard says to something like input is (null | undefined) or input is MySpecificInterface if you plan to do something meaningful in both true and false cases. This trickiness may also be a sign that you want to separate your validation into two checks:
if(typeGuard(myObject)) {
if(isValid(myObject)) {
// do something with valid object
} else {
// do something with invalid object
}
}
// do nothing without an object to act upon

What is the purpose of the "!" in this TypeScript method call? [duplicate]

When looking at the sourcecode for a tslint rule, I came across the following statement:
if (node.parent!.kind === ts.SyntaxKind.ObjectLiteralExpression) {
return;
}
Notice the ! operator after node.parent. Interesting!
I first tried compiling the file locally with my currently installed version of TS (1.5.3). The resulting error pointed to the exact location of the bang:
$ tsc --noImplicitAny memberAccessRule.ts
noPublicModifierRule.ts(57,24): error TS1005: ')' expected.
Next I upgraded to the latest TS (2.1.6), which compiled it without issue. So it seems to be feature of TS 2.x. But the transpilation ignored the bang completely, resulting in the following JS:
if (node.parent.kind === ts.SyntaxKind.ObjectLiteralExpression) {
return;
}
My Google fu has thus far failed me.
What is TS's exclamation mark operator, and how does it work?
That's the non-null assertion operator. It is a way to tell the compiler "this expression cannot be null or undefined here, so don't complain about the possibility of it being null or undefined." Sometimes the type checker is unable to make that determination itself.
It is explained in the TypeScript release notes:
A new ! post-fix expression operator may be used to assert that its operand is non-null and non-undefined in contexts where the type checker is unable to conclude that fact. Specifically, the operation x! produces a value of the type of x with null and undefined excluded. Similar to type assertions of the forms <T>x and x as T, the ! non-null assertion operator is simply removed in the emitted JavaScript code.
I find the use of the term "assert" a bit misleading in that explanation. It is "assert" in the sense that the developer is asserting it, not in the sense that a test is going to be performed. The last line indeed indicates that it results in no JavaScript code being emitted.
Louis' answer is great, but I thought I would try to sum it up succinctly:
The bang operator tells the compiler to temporarily relax the "not null" constraint that it might otherwise demand. It says to the compiler: "As the developer, I know better than you that this variable cannot be null right now".
Non-null assertion operator
With the non-null assertion operator we can tell the compiler explicitly that an expression has value other than null or undefined. This is can be useful when the compiler cannot infer the type with certainty but we have more information than the compiler.
Example
TS code
function simpleExample(nullableArg: number | undefined | null) {
const normal: number = nullableArg;
// Compile err:
// Type 'number | null | undefined' is not assignable to type 'number'.
// Type 'undefined' is not assignable to type 'number'.(2322)
const operatorApplied: number = nullableArg!;
// compiles fine because we tell compiler that null | undefined are excluded
}
Compiled JS code
Note that the JS does not know the concept of the Non-null assertion operator since this is a TS feature
"use strict";
function simpleExample(nullableArg) {
const normal = nullableArg;
const operatorApplied = nullableArg;
}
Short Answer
Non-null assertion operator (!) helps the compiler that I'm sure this variable is not a null or undefined variable.
let obj: { field: SampleType } | null | undefined;
... // some code
// the type of sampleVar is SampleType
let sampleVar = obj!.field; // we tell compiler we are sure obj is not null & not undefined so the type of sampleVar is SampleType
My understanding is the ! operator do the same thing like NonNullable.
let ns: string | null = ''
// ^? let ns: string | null
let s1 = ns!
// ^? let s1: string
let s2 = ns as NonNullable<typeof ns>
// ^? let s2: string

What does exclamation mark "!." after an object property means in Javascript [duplicate]

When looking at the sourcecode for a tslint rule, I came across the following statement:
if (node.parent!.kind === ts.SyntaxKind.ObjectLiteralExpression) {
return;
}
Notice the ! operator after node.parent. Interesting!
I first tried compiling the file locally with my currently installed version of TS (1.5.3). The resulting error pointed to the exact location of the bang:
$ tsc --noImplicitAny memberAccessRule.ts
noPublicModifierRule.ts(57,24): error TS1005: ')' expected.
Next I upgraded to the latest TS (2.1.6), which compiled it without issue. So it seems to be feature of TS 2.x. But the transpilation ignored the bang completely, resulting in the following JS:
if (node.parent.kind === ts.SyntaxKind.ObjectLiteralExpression) {
return;
}
My Google fu has thus far failed me.
What is TS's exclamation mark operator, and how does it work?
That's the non-null assertion operator. It is a way to tell the compiler "this expression cannot be null or undefined here, so don't complain about the possibility of it being null or undefined." Sometimes the type checker is unable to make that determination itself.
It is explained in the TypeScript release notes:
A new ! post-fix expression operator may be used to assert that its operand is non-null and non-undefined in contexts where the type checker is unable to conclude that fact. Specifically, the operation x! produces a value of the type of x with null and undefined excluded. Similar to type assertions of the forms <T>x and x as T, the ! non-null assertion operator is simply removed in the emitted JavaScript code.
I find the use of the term "assert" a bit misleading in that explanation. It is "assert" in the sense that the developer is asserting it, not in the sense that a test is going to be performed. The last line indeed indicates that it results in no JavaScript code being emitted.
Louis' answer is great, but I thought I would try to sum it up succinctly:
The bang operator tells the compiler to temporarily relax the "not null" constraint that it might otherwise demand. It says to the compiler: "As the developer, I know better than you that this variable cannot be null right now".
Non-null assertion operator
With the non-null assertion operator we can tell the compiler explicitly that an expression has value other than null or undefined. This is can be useful when the compiler cannot infer the type with certainty but we have more information than the compiler.
Example
TS code
function simpleExample(nullableArg: number | undefined | null) {
const normal: number = nullableArg;
// Compile err:
// Type 'number | null | undefined' is not assignable to type 'number'.
// Type 'undefined' is not assignable to type 'number'.(2322)
const operatorApplied: number = nullableArg!;
// compiles fine because we tell compiler that null | undefined are excluded
}
Compiled JS code
Note that the JS does not know the concept of the Non-null assertion operator since this is a TS feature
"use strict";
function simpleExample(nullableArg) {
const normal = nullableArg;
const operatorApplied = nullableArg;
}
Short Answer
Non-null assertion operator (!) helps the compiler that I'm sure this variable is not a null or undefined variable.
let obj: { field: SampleType } | null | undefined;
... // some code
// the type of sampleVar is SampleType
let sampleVar = obj!.field; // we tell compiler we are sure obj is not null & not undefined so the type of sampleVar is SampleType
My understanding is the ! operator do the same thing like NonNullable.
let ns: string | null = ''
// ^? let ns: string | null
let s1 = ns!
// ^? let s1: string
let s2 = ns as NonNullable<typeof ns>
// ^? let s2: string

Is "undefined" in Javascript an error or just a notice?

Is the undefined message in the pop up or console log (e.g. when calling a variable that doesn't exist) an ERROR message or just a NOTICE message?
In PHP there is a difference, so, looking for your explanation on this subject.
Neither, it is a value (or a stringification of a value in the case of an alert)
Whether or not you can ignore the fact that a variable/property/whatever is undefined depends on the needs of the program you are writing. If a message displays "undefined" when it should display "sweet cuppin' cakes", then that would be a logic error; conversely, if a message displays undefined when it is merely intended to reflect an internal state that can legitimately be undefined, it would not be an error.
It sounds to me like an incomplete error message; like when a developer prints "This should never appear!11" Undefined is nothing more than a value, so seeing it on its own does not assign any meaning or importance to the message.
'undefined' means exactly what it says - you have referenced a variable name that is not defined.
Some languages, like Python, are stricter about this kind of thing, and will throw an error if you try to do this.
Javascript assumes you know what you are doing, and so doesn't complain.
Undefined is, what its name says, a sign for something beeing not defined, like
var a=new Array(10);
It is an array: Array.isArray(a)is true, a.length is 10; but all it contains are undefined values: e.g. a[5] is undefined. So it is no error.
ERROR message or just a NOTICE message?
Neither nor.
undefined is a special data type. For example, a common case is a missing parameter in a function call:
var foobar = function(val)
{
alert(typeof val); // alerts 'undefined'
alert(foobar.length); // throws an error
}
foobar();
The author of this example function should have checked for the type of val before trying to access the length property.

Categories

Resources