ForestG
ForestG

Reputation: 18123

Typescript expression with nullcheck is possibly undefined but only in Angular template

I have the following code:

ts:

  get myArray(): any[]{
    return [1,2,3];
  }

template:

<p>Test:</p>
<div *ngIf="myArray?.length > 2">
  array has more than 2 items
</div>

For this, the compiler tells me:

Error in src/app/app.component.html (2:13)
Object is possibly 'undefined'.

Why? The code works just fine, if I write the exact same expression in the component:

  constructor(){
    if(this.myArray?.length > 2){
      console.log("yay")
    }
  }

Stackblitz example: https://stackblitz.com/edit/angular-ivy-hhpoag?file=src%2Fapp%2Fapp.component.ts

tsconfig:

{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "strict": true,
    "suppressImplicitAnyIndexErrors": true,
    "sourceMap": true,
    "declaration": false,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "module": "esnext",
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "es2015",
    "typeRoots": ["node_modules/@types"],
    "lib": ["es2018", "dom"]
  },
  "angularCompilerOptions": {
    "enableIvy": true,
    "fullTemplateTypeCheck": true,
    "strictInjectionParameters": true,
    "strictTemplates": true
  }
}

Upvotes: 1

Views: 521

Answers (1)

ForestG
ForestG

Reputation: 18123

One of my collegues pointed out the source of the error:

The Angular Template Engine (probably) overcasts the type of my getter. The myArray type will change from any[] to any[] | undefined. If we do that the typescript code in the component will fail also:

import { Component } from '@angular/core';
import { FormArray, FormControl, FormGroup } from '@angular/forms';

@Component({
  selector: 'my-app',
  template: ``
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {

  get myArray(): any[] | undefined {    // causes build time error too without a template
    return [1,2,3];
  }

  constructor(){
    if(this.myArray?.length > 2){
      console.log("yay")
    }
  }
}

One possible solution is to check the value and replace it if needed, like this in the template:

<p>Test:</p>
<div *ngIf="(myArray?.length ?? 0) > 2">
  array has more than 2 items
</div>

StackBlitz: https://stackblitz.com/edit/angular-ivy-muwdqu?file=src/app/app.component.html

Upvotes: 1

Related Questions