6

I have a component which accepts an @Input like this:

@Input() thing:Thing; // error!

This is passed to the component in the usual manner:

<my-component [thing]="thatThing"></my-component>

I think because of strict mode, I get the following compiler error: Property 'thing' has no initializer and is not definitely assigned in the constructor. Is there a way to get rid of that without filling with dummy data and while keeping strict mode (if that is indeed the cause), and just rely on the input being populated from whoever is instantiating the component? I don't really have a default value to assign to thing, and null or undefined don't seem to work, either.

Carlos Romero
  • 698
  • 8
  • 18

3 Answers3

5

While using @Input() thing!: Thing; does indeed remove the compiler warning, it's not the best idea to ignore the fact that @Inputs can always be undefined

If you want to keep it strict, you can use @Input() thing: Thing | undefined;

If you do want to use @Input() thing!: Thing;, I suggest safeguarding against it like this:

public ngAfterViewInit(): void {
  // thing should be defined here, if it was assigned a value
  if(!this.thing){
    throw new Error('thing is not defined, please provide a value.');
  }
}
2

You defined a class variable that is empty (undefined) but you declared it to be of type Thing. This is actually wrong because in this moment is undefined and not Thing

The correct typing would be "Thing OR undefined":

@Input() thing: Thing | undefined;
// or shorter
@Input() thing?: Thing;

Doing so will make the compiler complain if you want to use this.thing and don't check if it actually exists first:

this.thing.toString(); // Error

if (typeof this.thing !== 'undefined') {
   this.thing.toString(); // Ok
}

This may be kind of annoying but is actually correct because all inputs can be undefined if one uses the component without defining them:

<my-component></my-component>

If you want to get around this (which I do not recommend) because you know "me as a human person I am perfect and will never ever make the mistake not defining that input" you can tell the compiler that your variable will be defined:

@Input() thing!: Thing;
Mick
  • 8,203
  • 10
  • 44
  • 66
1

You can add an exclamation mark to indicate to the typescript compiler to ignore the missing default value.

@Input() thing!: Thing;

Daniel B
  • 8,770
  • 5
  • 43
  • 76
  • You can do that but it actually bypasses strict mode and will result in errors if `this.thing` is undefined which can definitely be the case. You answer has more upvotes than the accepted answer, but it recommends a bad practice. What he actually wanted to do is to define the variable as `Thing | undefined`: `@Input() thing: Thing | undefined;` – Mick Aug 12 '21 at 14:40