Why does TypeScript ask me to initialise a property if I'm getting it's value from local reference?

I just started to learn Angular.

This is my custom component’s Template

    <div class="row">
  <div class="col-xs-12">
    <form action="">
      <div class="ro">
        <div class="col sm-5 form-group">
          <label for="name">Name</label>
          <input type="text" id="name" class="form-control" #nameInput />
        <div class="col-sm-2 form-group">
          <label for="amount">Amount</label>
          <input type="number" id="amount" class="form-control" #amountInput />
      <div class="row">
        <div class="col-xs-12">
          <button class="btn btn-success" type="submit" (click)="onAddItem()">
          <button class="btn btn-danger" type="button">Delete</button>
          <button class="btn btn-primary" type="button">Clear</button>

This is respective TypeScript file

import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';

  selector: 'app-shopping-edit',
  templateUrl: './shopping-edit.component.html',
  styleUrls: ['./shopping-edit.component.css'],
export class ShoppingEditComponent implements OnInit {
  @ViewChild('nameInput') nameInputRef: ElementRef;
  @ViewChild('amountInput') amountInputRef: ElementRef;

  constructor() {}

  ngOnInit(): void {}
  onAddItem() {}

I get error to initialise the variables nameInputRef and amountInputRef. But I’m receiving these values from the form. How do I solve this?

>Solution :

Typescript has no knowledge that you are grabbing those values from something defined in the template. Additionally, they will not be initialized until the view is initialized in the angular lifecycle, and you may potentially be attempting to access they when still undefined.

The answer to your question is to use the non null assertion operator !, as follows

export class ShoppingEditComponent implements OnInit {
 @ViewChild('nameInput') nameInputRef!: ElementRef;
 @ViewChild('amountInput') amountInputRef!: ElementRef;

However, be wary that this is misusing the operator, because, as mentioned, it is possible to access while it is still undefined.

A second method you could use is to expand the type to allow undefined

@ViewChild('nameInput') nameInputRef: ElementRef | undefined;

However when accessing any property, you would have to use the non null assertion operator


As an aside, If these elements are static within your component, (not subject to *ngIf or any conditional rendering) you can mark them as static. This will allow you to access them earlier in the component lifecycle, via ngOnInit.

@ViewChild('nameInput', { static: true }) nameInputRef: ElementRef;
@ViewChild('amountInput', { static: true }) amountInputRef: ElementRef;

I always mark a ViewChild as static if it meets these criteria so I have access to them as early in the lifecycle as possible

Leave a Reply