Menu

Angular Best Practices from the Start

February 20th, 2021

One of the highest priorities for Angular is to enable best practices from the start. We want you to feel comfortable building a large enterprise user interface the same way as creating a to-do app.

We apply this mindset in the framework’ APIs, developer tooling, best practices, and documentation. A few examples are the investment in TypeScript we did early on, enabling dependency injection by default for more flexible and testable code, as well as performance budgets that every Angular application follows.

fence wire with heart locks attached.
https://pixabay.com/photos/heart-pink-deans-rope-love-hearts-2381569/

Over time we’ve been doing a lot of work in this space. At the same time, we’ve been trying to balance strictness and accessibility. We don’t want to make Angular unteachable and impossible to learn by newcomers to Web development. An excellent example of this is strict mode that we’ve been moving towards cautiously.

In the blog post “Angular CLI Strict Mode,” we described what it enables and asked for community feedback. We spent many hours talking to Angular developers, trainers and dug into the Angular CLI telemetry to find that close to 70% of people have opted into strict mode since we enabled the prompt. Based on all this aggregated data, we decided on how to move forward.

chart showing use of strict mode CLI telemetry. 10.8% of users have the no strict flag enabled.
Distribution of projects opted into strict mode

We’re happy to announce that we’ll be enabling strict mode by default for all new projects starting from version 12. You’d still be able to opt-out bypassing the –no-strict option when creating a new workspace.

Strict mode settings

Based on the feedback we received from the community, we changed the definition of strict mode a little. As part of version 12, we’re going to enable:

  • Strict mode in TypeScript, as well as other strictness flags recommended by the TypeScript team. Specifically, strict, forceConsistentCasingInFilenames, noImplicitReturns and noFallthroughCasesInSwitch
  • Strict Angular compiler flags strictTemplates, strictInputAccessModifiers and strictInjectionParameters
  • Reduced bundle size budgets by ~75%

Starting from version 12, we’re going to remove the strict mode prompt, and all new projects will have these settings enabled from the start.

Enable for existing projects

Although we’ll not be migrating existing projects to strict mode, you can opt-in pretty quickly. All you’d need to do is to enable a few flags in your tsconfig.json for your Ivy apps:

{
  ...
  "compilerOptions": {
    ...
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    ...
  },
  "angularCompilerOptions": {
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  }
}

Additionally, you can revisit your bundle budgets in angular.json. Strict mode uses the following configuration:

"budgets": [
  {
    "type": "initial",
    "maximumWarning": "500kb",
    "maximumError": "1mb"
  },
  {
    "type": "anyComponentStyle",
    "maximumWarning": "2kb",
    "maximumError": "4kb"
  }
]

Implications

Having stricter type checking will allow you to catch many bugs early on. That’s a best practice we’ve been using for all the TypeScript projects in Google’s monorepo for a while, and we’re excited to enable it by default for everyone. Based on the paper “To Type or Not to Type: Quantifying Detectable Bugs in JavaScript,” you’ll be able to catch significantly more issues at build-time with strict null checks enabled by default.

You should expect a few new, common type errors that will start popping up.

Strict TypeScript flags

This snippet will no longer compile for new apps using v12 because of the strictPropertyInitialization:

@Component({...})
class AppComponent {
  // Property 'title' has no initializer and is not
  // definitely assigned in the constructor.ts(2564)
  @Input() title: string;
}
Fixing the problem would be as simple as setting a value of the title property:
@Component({...})
class AppComponent {
  @Input() title = '';
}

You may find yourself in a similar situation when you forget to initialize a property or set its value:

class Employee {
  // Member employees' implicitly has an 'any' type.ts(7008)
  employee;
}

TypeScript here will throw an error that the employee has an implicit type any. To fix the problem, you can initialize the value or set an explicit type.

There are a few other similar issues that you can find more about here.

Strict template type checking

With the Ivy compiler and the language service, you’ll be able to experience the power of TypeScript’s type system in your templates!

The new language service is based on the Ivy compiler, which uses TypeScript for type checking. Using this mechanism means that your templates will be as strict as the rest of your application.

On rare occasions, we need to cast an expression to any. Having stricter type checking in templates, you may need to do the same. Angular’s template syntax allows you to do this using:

<div>{{ $any(user) }}</div>

Tighter budgets

Last but not least, the strict mode will also tighten your size budgets. If you introduce a third-party dependency that’s not tree-shakable or exceeds the size of the bundle you’re aiming for, you’ll get a build-time error.

You can opt-out of this feature by updating your angular.json configuration, but we’re strongly recommending you to keep their existing values so you can ensure your app stays fast over time.

If you get a build-time failure because your resources exceed the size budgets, please review our performance optimization practices to optimize your application.

screenshot of the build tool alerting the user of build budget violations.
Failing performance budget

Higher quality software for everyone

Type systems have been a thriving field of research and development for decades now. Having specific types and advanced checks allows us to catch bugs early on before we ship our app to production and enables a better development experience.

The more specific types we have, the better our text editor and IDE can support us with auto-completion and other hints. Good typing enables advanced static code analysis for other tools, including schematics. Update schematics will transform your project more confidently, having better type information.

Our goal is to enable you to seamlessly solve real-world problems through software with a complete and opinionated solution. We’re excited to take this step forward with stricter and more complete tooling.

The original post With Best Practices from the Start.