11

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:

enter image description here

Ole
  • 41,793
  • 59
  • 191
  • 359
  • sry, wrong link https://stackoverflow.com/questions/42273853/in-typescript-what-is-the-exclamation-mark-bang-operator-when-dereferenci – Julius Dzidzevičius Nov 28 '19 at 17:35
  • Yes - Much better - thanks! – Ole Nov 28 '19 at 17:36
  • Not really sure why we would use that in an Angular context though? Why use this on an Angular @Input field? – Ole Nov 28 '19 at 17:37
  • 2
    https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#non-null-assertion-operator – Alexander Staroselsky Nov 28 '19 at 17:38
  • In the handbook scenario it makes perfect sense, but I'm still not sure why they are adding it to the `@Input` field. The use cases within Angular always assume that these are not null and we don't get any compilation errors? – Ole Nov 28 '19 at 17:46
  • In other words suppose we remove the `!`. What is the effect in this case? – Ole Nov 28 '19 at 17:47
  • In some places in docs there are `!` and links to issues. However, if you enable strict null checks you would need these `!` everywhere – Sergey Nov 28 '19 at 17:55
  • Looking at it more closely it does not look like it really makes sense because the `createToken` method is the action that creates and sets the token, so it's not really an `@Input` ... WDYT? – Ole Nov 28 '19 at 18:02

1 Answers1

16

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.

enter image description here

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.

enter image description here

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!

frido
  • 13,065
  • 5
  • 42
  • 56
  • So does it make sense to use it in this case, because it's not a parameter that is included in the constructor and it's also something that is created and set by the `createToken` method, so to me it seems almost like the reverse of what the code wants to be doing? – Ole Nov 28 '19 at 19:35
  • 1
    Values for `@Input` properties are usually passed to a component from a parent component. As the compiler doesn't know this is happening and the property isn't initialized in any other way known to the compiler it will throw an error according to the `strictPropertyInitialization` option. So they have to tell the compiler not to care about the property being undefined at initialization. They could have used `@Input() token: StripeToken | undefined` to allow undefined values or `!` to not check for undefined. They decided to do the later. – frido Nov 28 '19 at 20:03
  • That makes sense - however if you look at their usage example on the main page: https://github.com/AckerApple/stripe-angular It turns out they don't set a token on the component, because the token is created by the Stripe API, so I think perhaps they misunderstood what that operator is for ... I also don't think Angular / Typescript does anything with it ... it does not matter whether it is there or not in the Angular scenario ... Would you agree? – Ole Nov 28 '19 at 20:47
  • I tested it on a new Angular project and it does not even allow it - so it seems that this is never something we would want to do in an Angular project. – Ole Nov 28 '19 at 21:44
  • I tested this again with a type, but without initializing the property on the element and Angular does not throw a compiler error ... – Ole Dec 25 '19 at 21:33