5

I have a HeaderComponent that takes an object of form {title: string, short_desc: string} as its input property.

@Component({
  selector: 'header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss']
})
export class HeaderComponent implements OnInit {
  @Input() data: { title: string, short_desc: string };

  constructor() { }

  ngOnInit() { }
}

Here is how I define data that will be passed to HeaderComponent:

@Component({
  templateUrl: './my-custom.component.html',
  styleUrls: ['./my-custom.component.scss']
})
export class MyCustomComponent implements OnInit {
    public headerData: {title: string, short_desc: string};

    constructor() {
        this.headerData = {
            title: 'Settings Page',
            short_desc: 'Update your settings',
        }
    }

  ngOnInit() { }
}

Now, I need to use HeaderComponent in quite a few components. So I created a file header-data.ts which looks like this:

export interface HeaderData {
    title: string;
    short_desc: string;
}

In order to make HeaderComponent work, in every component that uses it, I need to import HeaderData interface. This can sometimes look ugly and can break, when I decide to restructure my application.

My question is: how to use HeaderData interface without need for ugly nested imports like ../../../../hero-data.ts, or in-line object type definitions. Or maybe what I do is not the best way to go about this problem here?

1 Answer 1

8

You apparently noticed how you usually import multiple Angular classes from @angular/... modules in a single line. That's is the Barrel feature. Please look at the Barrel file description in the Angular docs.

While reading that text, you have to understand the difference between a JavaScript module and an Angular module. The former is a source file, the latter is a class decorated with @NgModule.

Since interface is not a JavaScript notion, but an abstraction in TypeScript, it is needed only in the editor and during transpilation. Module loaders don't use interface file declarations. So you can use a trick and declare it as a TypeScript definition.

Rename your file to header-data.d.ts, and use the word declare instead of export like the following.

declare interface HeaderData {
  title: string;
  short_desc: string;
}

So TypeScript will be able to find the HeaderData name at design time. This trick relies on the "**/*.d.ts" line in the "include" array in the tsconfig.spec.json file.

Sign up to request clarification or add additional context in comments.

3 Comments

That's a nice one! However if I understand correctly, it still requires to use long relative imports (like in the example at the end of my question) in every component file.
@an0o0nym I have added an idea how to use an interface without importing it explicitly.
barrel link is broken

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.