Where to put your Angular models?

Before we go into detail - it's worth understanding what we mean by models:

  • entity classes?

  • enums?

  • interfaces?

Could be all of them - depending on who you ask.

I personally like to differentiate between interfaces and models as two distinct things:

  • interfaces are used to define the shape of my Typescript entities

  • models are used to define the actual value of my interfaces

How to organize your models in your Angular Project Structure

Every module may have a set of entities (models, enums, etc.) that are either private or public to the module itself.

Let's assume we have a module called UsersModule. We want to define, for every entity, a sensible folder structure:

- users
    - components
    - services
    - enums
        - roles.enum.ts
    - interfaces
        - user.interface.ts
    - models

As you may have noticed, enums, interfaces and models all have their own folder, and it's important not to mix them to keep them well-organized.

Entities Visibility

There are a few rules that I tend to follow to make sure my project is well-organized.

Use a shared library for entities used outside of your modules

It's important to notice that a module should only contain the entities that are not shared with other modules, and hence that are private to that module.

But - Why?

Imagine we have a mono-repo with other applications or libraries written in different technologies (ex. Express, Stencil, React, etc.): you may not want to import your types from a different technology.

💡 Solution

Create a separate library (for example, called @enterprise/interfaces) that exposes your global entities. This is particularly recommended if you're using Nx to structure your project.

Otherwise, consider creating a typescript repository to expose your global entities to different repositories.

Admittedly, this is not great - but if you have a large team of teams using the same interfaces, it could be really important to keep them in sync.

Never export an interface from a Service

This is a pattern that I quite dislike - and I see used very often.

Defining an interface within a Service (or a Component) is generally fine - although not something I normally do. It's all good - as long as it is not exported.

Why is that?

  • A component should not import a service simply to get an Interface

  • A component may simply use Typescript inference instead of using that Interface

  • If the interface is reused and is used in a way that inference could not work, then it should be defined in its own file

Hopefully, this answered your questions - but if not, please do send me an email and I'd love to expand on the subject.

Thank you for reading, I hope you enjoyed this article. If you did, consider following me on Twitter.