0

While reading Angular 2 source code, I came across NgForOfContext<T> which sources can be found in the official repository here and, below here, the part which brought interest.

In particular the following syntax is something I have never seen in neither plain Javascript nor in Typescript:

private _applyChanges(changes: IterableChanges<T>) {
    const insertTuples: RecordViewTuple<T>[] = [];
    changes.forEachOperation(
        (item: IterableChangeRecord<any>, adjustedPreviousIndex: number, currentIndex: number) => {
          if (item.previousIndex == null) {
            const view = this._viewContainer.createEmbeddedView(
                this._template, new NgForOfContext<T>(null !, this.ngForOf, -1, -1), currentIndex);
            const tuple = new RecordViewTuple<T>(item, view);
            insertTuples.push(tuple);
          } else if (currentIndex == null) {
            this._viewContainer.remove(adjustedPreviousIndex);
          } else {
            const view = this._viewContainer.get(adjustedPreviousIndex) !;
            this._viewContainer.move(view, currentIndex);
            const tuple = new RecordViewTuple(item, <EmbeddedViewRef<NgForOfContext<T>>>view);
            insertTuples.push(tuple);
          }
        });

I am talking about the null ! in line:

this._template, new NgForOfContext<T>(null !, this.ngForOf, -1, -1), currentIndex);

The first argument is null, followed by a logical not (!). In my attampt to understand this code, I have double checked and as far as I know, null is a primitive Javascript (and TS) type and it makes no sense to have a null !. Which moreover would make more syntactical sense if it were !null (not null) that returns true

To make sure I was wrong, I tried to compile it, but to my surprise, it fails. It complains about Unexpected )

Now, obviously Angular works. We all know that. Therefore I must be missing something. Pray, resolve this killer mystery...

Attersson
  • 4,755
  • 1
  • 15
  • 29
  • probably answered here https://stackoverflow.com/questions/42273853/in-typescript-what-is-the-exclamation-mark-bang-operator-when-dereferenci – bryan60 May 24 '18 at 19:09
  • ...ah. And why does it not compile? – Attersson May 24 '18 at 19:10
  • you're probably using it wrong, you should post how you're actually using it and the error. – bryan60 May 24 '18 at 19:12
  • just a tip, angular doesn't preserve whitespace when compiling it's typescript, so the space in there is valid fro them. if you are, then the space will cause an issue. Depending on your typescript version, this may or may not be the default behavior. – bryan60 May 24 '18 at 19:16
  • well not a space problem since I compiled Angular sources as they are, but I will note the tip – Attersson May 24 '18 at 19:21

1 Answers1

3

This is called the Non-null assertion operator, It is used when we have a value that can be null to assert that it is not null

  var nullable: string | null = null;
  var nonNullable: string = "";

  nonNullable = nullable // Error 
  nonNullable = nullable! // Ok, we asserted it is not null

In this case it is used (rather counter intuitively) to assert null is not null

nonNullable = null! // Ok, we assert null is not null 

Playground link

Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357