Home > OS >  Angular Typescript access property on object with dot notation?
Angular Typescript access property on object with dot notation?

Time:03-23

I have an object L2Language with three properties: short, long, and videos. It works as expected in the child component and now I'm trying to pass the object from the child component to the parent component via an event emitter:

(L2LanguageEvent)="L2LanguageEventHandler($event)"

The object is passing to the parent. When I view the object in the console with console.table(L2LanguageEvent); the properties are there:

enter image description here

but when I log a property on the object with console.log(L2LanguageEvent.short); I'm told that the property isn't on the object:

Property 'short' does not exist on type 'object'.

Here's my parent component:

import { Component, OnInit } from '@angular/core';
import { L2Language } from './home-toolbar/home-toolbar.component';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
  language: L2Language;

  ngOnInit(): void {
    console.log(this.language); // doesn't work
  }

  L2LanguageEventHandler(L2LanguageEvent: object) {
    console.table(L2LanguageEvent); // works, you see the result above
    console.log(L2LanguageEvent.short); // doesn't work
    console.log(L2LanguageEvent['short']); // doesn't work
    this.language = L2LanguageEvent; // doesn't work
  }
}

console.log(this.language); returns undefined. This suggests that the interface L2Language was never imported. I'm not getting the error Cannot find module so it's not a path problem. Or maybe it's saying the L2Language was imported but the property values are undefined? This is true but it shouldn't cause the error saying that the property doesn't exist on the object.

console.log(L2LanguageEvent.short); returns the error Property 'short' does not exist on type 'object'.

console.log(L2LanguageEvent['short']); returns two errors:

Element implicitly has an 'any' type because expression of type '"short"' can't be used to index type '{}'.

Property 'short' does not exist on type '{}'.

this.language = L2LanguageEvent; returns the error

Type '{}' is missing the following properties from type 'L2Language': short, long, videos

Thanks for your help.

CodePudding user response:

The problem is with this part of the code

  L2LanguageEventHandler(L2LanguageEvent: object) { //CHANGE THIS object
    console.table(L2LanguageEvent); // works, you see the result above
    console.log(L2LanguageEvent.short); // doesn't work
    console.log(L2LanguageEvent['short']); // doesn't work
    this.language = L2LanguageEvent; // doesn't work
  }

Instead of object just use your interface.

 L2LanguageEventHandler(L2LanguageEvent: L2Language){}

CodePudding user response:

I'd made two mistakes. First, in the child component I'd written:

export interface L2Language = {
  short: string;
  long: string;
  videos: string;
};

export class HomeToolbarComponent implements OnInit {
  @Output() L2LanguageEvent = new EventEmitter<object>();
}

This is correct:

export interface L2Language = {
  short: string;
  long: string;
  videos: string;
};

export class HomeToolbarComponent implements OnInit {
  @Output() L2LanguageEvent = new EventEmitter<L2Language>();

Second, in the parent component this was incorrect:

L2LanguageEventHandler(L2LanguageEvent: object) {
    console.table(L2LanguageEvent);
    console.log(L2LanguageEvent.short);
  }

This is correct:

 L2LanguageEventHandler(L2LanguageEvent: L2Language) {
    console.table(L2LanguageEvent);
    console.log(L2LanguageEvent.short);
  }

Rereading the TypeScript Handbook, I see that object isn't a type. You make an object, give it a name, and then the type is the name. In fact, I can make my object a type instead of an interface:

export type L2Language = {
  short: string;
  long: string;
  videos: string;
};

Note that there's an = in there now! The TypeScript Handbook explains that

the key distinction is that a type cannot be re-opened to add new properties vs an interface which is always extendable.

You don't have to name an object, you can make in anonymous. That might be good for an object that it used in one function but for an object that's passed between components it should be a named type or interface.

Thanks Daniel!

  • Related