This question already has answers here:
In Typescript, what is the ! (exclamation mark / bang) operator when dereferencing a member?
(5 answers)
Closed 3 years ago.
I've been seeing this creep up in a few places now but have not found any answers on it.
I'm curious what the '!' bang does in the angular syntax.
From the Angular documentation:
The non-null assertion operator ( ! )
As of Typescript 2.0, you can enforce strict null checking with the
--strictNullChecks flag. TypeScript then ensures that no variable is unintentionally null or undefined.
In this mode, typed variables disallow null and undefined by default.
The type checker throws an error if you leave a variable unassigned or
try to assign null or undefined to a variable whose type disallows
null and undefined.
The type checker also throws an error if it can't determine whether a
variable will be null or undefined at runtime. You may know that can't
happen but the type checker doesn't know. You tell the type checker
that it can't happen by applying the post-fix non-null assertion
operator (!).
The Angular non-null assertion operator (!) serves the same purpose in
an Angular template.
For example, after you use *ngIf to check that hero is defined, you
can assert that hero properties are also defined.
<!-- No hero, no text -->
<div *ngIf="hero">
The hero's name is {{hero!.name}}
</div>
When the Angular compiler turns your template into TypeScript code, it
prevents TypeScript from reporting that hero.name might be null or
undefined.
Unlike the safe navigation operator, the non-null assertion operator
does not guard against null or undefined. Rather it tells the
TypeScript type checker to suspend strict null checks for a specific
property expression.
You'll need this template operator when you turn on strict null
checks. It's optional otherwise.
Its called the "Non-null assertion operator" and has nothing todo with Angular perse, it is from typescript.
let s = e!.name; // Assert that e is non-null and access name
Related
I was very surprised to see the following behavior in Node 14.18.0:
> {}?.fun();
Uncaught TypeError: b?.fun is not a function
> undefined?.fun();
undefined
I understand why the first statement throws a TypeError. {}?.fun is undefined, which is not callable. But undefined?.fun is also undefined, so why can it be called without throwing? What part of the ECMAScript specification defines this behavior? Did the ECMAScript working group provide any reasons why it should work this way?
During optional chaining, if the current value within the chain is null or undefined, the expression short-circuits with a return value of undefined.
This is in the official docs:
The ?. operator is like the . chaining operator, except that instead of causing an error if a reference is nullish (null or undefined), the expression short-circuits with a return value of undefined. When used with function calls, it returns undefined if the given function does not exist.
Since {} is an actual object—without a method called fun()—it blows up, because you called a function that did not exist.
To fix your issue, you will need to call the function with optional chaining:
console.log(({})?.fun?.()); // undefined
the work of? and say that possibly the value is undefined
normally used like this in typescript
console.log(myobj?.value ?? 'does not exist');
in javascript "?" it's useless
"?" doesn't do anything, it just signals that the value can be undefined, so when you put an object, it returns an error because this property doesn't exist in your object, whereas in undefined javascript it just ignores everything
This question already has answers here:
Null-safe property access (and conditional assignment) in ES6/2015
(11 answers)
Closed 2 years ago.
I've been programming a lot in Swift recently. Today I did some work in JavaScipt when question popped up to me:
Is there something similar to optional chaining in JavaScript? A way to prevent undefined is not an object without any variables?
Example:
function test(){
if(new Date() % 2){
return {value: function(){/*code*/}};
}
}
test().value();
will fail half of time because sometimes test returns undefined.
The only solution I can think of is a function:
function oc(object, key){
if(object){
return object[key]();
}
}
oc(test(), 'value');
I would like to be able to do something like:
test()?.value()
The part after the question mark is only executed if test returned an object.
But this is not very elegeant. Is there something better? A magic combination of operators?
Edit I know I could rewrite test to return something. But I'm wondering if there's something like optional chaining. I'm not interested in a particular solution to the above example. Something that I also can use if have no control over the function returning undefined.
This is currently a Stage 4 proposal you can check on the progress of it here:
https://github.com/tc39/proposal-optional-chaining
You can use the babel plugin today:
https://www.npmjs.com/package/babel-plugin-transform-optional-chaining
Update 11th January 2020:
Babel now supports optional chaining by default
https://babeljs.io/blog/2020/01/11/7.8.0
The Optional Chaining operator is spelled ?.. It may appear in three positions:
obj?.prop // optional static property access
obj?.[expr] // optional dynamic property access
func?.(...args) // optional function or method call
Notes:
In order to allow foo?.3:0 to be parsed as foo ? .3 : 0 (as required for backward compatibility), a simple lookahead is added at the level of the lexical grammar, so that the sequence of characters ?. is not interpreted as a single token in that situation (the ?. token must not be immediately followed by a decimal digit).
Also worth checking out:
https://github.com/tc39/proposal-nullish-coalescing
https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-nullish-coalescing-operator
In plain JavaScript you have to do type checks or structure your code so that you know an object will exist.
CoffeeScript, a language that compiles down to JavaScript, provides an existential operator ?. for safe chaining if you're willing to consider a preprocessed language.
There's another discussion here about why you can't reproduce this behavior in JS.
There is also a discussion on the ESDiscuss forums about adding an existential operator to a future version of JavaScript. It doesn't seem very far along though, certainly nowhere close to practical use. More of an idea at this point.
Optional chaining has landed in JS. We can use optional chaining via the ?. operator in object property access. It allows us to try accessing properties of objects which might not exists (i.e. are undefined) without throwing an error.
Here is a code example:
const obj = {
foo: {
bar: 1
}
};
// If we try to access property which doesn't exists
// it just returns undefined
console.log(obj.baz);
try {
// Now we try to access a property of undefined which throws an error
obj.baz.foz;
} catch (e) {
console.dir(e.message);
}
// Now we use the optional chaining operator ?.
// We get undefined instead of an error
console.log(obj.baz?.foz);
console.log(obj.foo?.bar);
You can use
test() && test().value();
or
var testResult = test();
testResult && testResult.value();
If you ask me this is most similar to Swift's optional chaining.
var Obj = {Prop: {name: 'peter'}}
console.log(Obj.Prop.name)
console.log(Obj?.Prop?.name)
In the first sentence, you're just accessing object properties. The problem with that is that if you find Prop to be something other than an object, it will throw an exception. That's the reason of the optional chainig operator.
Lets say you try to do Obj.Prop2.name.
You'll get Uncaught TypeError: Cannot read property 'name' of undefined
if Instead you did Obj.Prop2?.name, You'll only receive undefined as a value, instead of an exception.
This is particularly useful when accessing deeply nested properties.
WARNING: This is a relatively new JS feature that's not yet implemented in all browsers, so be careful while using it for production applications.
Optional Chaining is finally in the JavaScript standard!
Here are a few examples:
// properties
foo?.bar
foo?.bar()
foo?.bar.baz()
foo?.bar?.baz()
// indexing
foo?.[0]
foo?.['bar']
// check if a function is defined before invoking
foo?.()
foo.bar?.()
foo?.bar?.()
And this is way better than what most people use for manually checking for nulls
Instead of evaluating
foo?.bar
to this little code snippet we are all used to writing
foo ? foo.bar : null
it actually evaluates to
foo == null ? undefined : foo.bar
which works for all the falsey values like an empty string, 0 or false.
Unrelated to the question, but you might also be interested in the ?? operator.
It has a similar purpose as || except it only checks for null or undefined.
For example:
foo ?? bar
would be the same as:
foo != null ? foo : bar
This is a very new feature, so even thought a lot of users already use a browser that supports this you will still want to use a tool to convert it to an older version of javascript.
What about returning a noop function that does nothing when the condition isn't met?
function test(){
if(new Date() % 2){
return {value: function(){/*code*/}};
}
return {value: function(){ /* just return a type consistent with the function above */ }
}
You can always return this; if test is a object method.
But why do you want to prevent such errors by creating mock functions?
This source code has #Input properties that end with a !. Here's an example:
#Input() token!:StripeToken
Why is it useful to have the ! in this case? Some of the comments have noted that it is a non null assertion operator, but why is it useful (Or perhaps not useful) to have that in this particular scenario?
I think the answer to this is that for Angular #Input properties having the non null assertion at the end of the property never makes sense but I wanted to see what the rest of you thought?
Update
I tried it on a new Angular project and I get this error:
A definite assignment assertion '!' is not permitted in this context.ts(1255)
So I don't think that it ever makes sense to inlude the ! operator on an #Input property. Here's a screenshot:
They use the compiler option strictPropertyInitialization so any class property not declared with type undefined and not initialized directly or in a constructor produces error TS2564.
To prevent this compiler error they use the definite assignment assertion modifier which tells TypeScript
... that a variable is indeed assigned for all intents and purposes,
even if TypeScript’s analyses cannot detect so.
Demo
Further reading: https://mariusschulz.com/blog/strict-property-initialization-in-typescript#solution-4-definite-assignment-assertion
Regarding your update
You didn't specify a type for the title variable in your example, that's why you get error TS1255. Using ! in this context is possible and makes sense!
Why do we have a question mark in a property? What is '?' marks significance.
<div *ngIf="heroForm.errors?.identityRevealed && (heroForm.touched || heroForm.dirty)" class="cross-validation-error-message alert alert-danger">
Name cannot match alter ego.
</div>
That is not a Typescript operator this is safe navigation operator or elvis operator.
Angular 2 has a safe navigation operator in templates.
? "Question Mark" is not a ternary operator in typescript, ? is used for safe loading the HTML doc while a component is generating the DOC for browser display.
Safe Navigation Operator (Elvis Operator):
The Safe Navigation Operator is also known as the "Elvis Operator". This operator is very useful to protect against null and undefined values in property paths. This operator allows us to navigate an object path in situations when we are not aware whether a path exists or not. It returns value of the object path if it exists, else it returns the null value. It is very useful to prevent null-reference exceptions.
Syntax:
object?.path
Refer:https://www.c-sharpcorner.com/article/introduction-to-safe-navigation-operator-in-angular-2/
A.S.: The question is about type of error, not about the phenomenon
"use strict" throws TypeError if system variables like NaN and undefined got changed.
But why is it a TypeError? Why not SyntaxError?
Edit: Really, it is not the SyntaxError here since there are no errors in syntax of the snippet.
But the root of the error lies in the fact, that some protected object cannot be changed manually; so, it is lkely the AccessError (there are no such, I know).
Then, why access-errors appear like type-ones?
In ES5, there are 6 different kinds of native errors:
EvalError
This exception is not currently used within this specification. This
object remains for compatibility with previous editions of this
specification.
RangeError
Indicates a numeric value has exceeded the allowable range.
ReferenceError
Indicate that an invalid reference value has been detected.
SyntaxError
Indicates that a parsing error has occurred.
TypeError
Indicates the actual type of an operand is different than the expected
type.
URIError
Indicates that one of the global URI handling functions was used in a
way that is incompatible with its definition.
In your case, the error is thrown because you attempt to assign a value to window.NaN or window.undefined, which are non-writable properties.
Before assigning the new value, the internal [[Put]] method checks [[CanPut]], which will return false because the property is non-enumerable. And therefore [[Put]] will throw.
So the problem is that the writability of the assigned reference (left operand in the assignment expression) is not the expected one. Then, among the 6 error kinds above, the most appropriate seems TypeError, even if writability is not exactly a type.
Because NaN and undefined are just read only properties of window. They are not operators (like > or +), or keywords (like var or class).
Trying to assign something to NaN gives the following error in Chrome:
TypeError: Cannot assign to read only property 'NaN' of object '#<Window>'
Because it's a valid argument that does not make sense. But it does not make sense in the SEMANTIC level, not the syntactic.
Here's an example:
1+1=42
This is wrong, but it's wrong in a different way than, say:
42 1 1 + =
You can read the first one as an arithmetic equation (one plus one equals forty-two). The second one, you can't even read.
The same goes here. the statement NaN=300; can be read in Javascript as "have NaN point to the value 300`. But when the parser submit this request to the engine, the engine goes "Nope, can't do this".
syntax error
In most programming & scripting languages this generally means that you've used an operator in the wrong place.
For more info on "syntax errors", have a look at this article: https://en.wikipedia.org/wiki/Syntax_error
type error
These occur when a data-type miss-matches some requirement.
For more information on "data-types", have a look at this article: https://en.wikipedia.org/wiki/Data_type
So, the type error is thrown because NaN and undefined are "data-types", which are global constants with a specific (designated) value, and "strict mode" prevents issues by not allowing to change these.