Fully Typed Angular Components

Alan Richardson - Oct 4 '21 - - Dev Community

Post Author: Stephen Cooper

Fully Typed Angular Components

As of AG Grid v26.1 we have applied full typings to the Angular components <ag-grid-angular> and <ag-grid-column>. All Input and Output properties now use the GridOption interface type for the property instead of any.

Applications with the strictTemplates Angular compiler option enabled (default for v12+ apps) will fail to compile if grid properties are misconfigured via the components.

Fully Typed Angular Components

If you configure your grids solely through the GridOptions interface these changes will not impact you as you will already be using the correct types.

Prerequisite Setup

Before we can take advantage of the new AG Grid typings we need to ensure our application is set up appropriately.

Template Type Checking (Required)

To have Angular provide template validation you must enable the strictTemplates flag under angularCompilerOptions in your tsconfig.json file. (This is only available if using Ivy).

{
  "compilerOptions": { ... },
  "angularCompilerOptions": {
    "strictTemplates": true
  }
}

// tsconfig.json

Enter fullscreen mode Exit fullscreen mode

Without this flag, Angular ignores the specified types for @Inputs and @Outputs and provides no compile-time validation for you. It is strongly recommended to enable strictTemplates for your application if possible. This is now enabled by default for new apps generated with the Angular CLI.

For more details see Template Type Checking.

Angular Language Service (Optional)

In the examples that follow we display screenshots that show code completion, navigation, hints and errors inside our template files. This is powered by the Angular Language Service. Instructions for setting it up for your editor of choice can be found in the Angular docs here.

The vast majority of the improved developer experience when using the new types comes from the Language Service.

Improved Developer Experience

To demonstrate the benefits of working with full typing we will add Input and Output properties to our grid and highlight the help we now get from the types.

Code Hints

Let us start by setting up conditional row classes as described in the Row Class Rules example. Previously you will have had to visit the documentation page to see the format of the object required as the Input had type any.

However, with our new types, if you hover over the template property it reveals the type of this property as rowClassRules: RowClassRules | undefined;.

Fully Typed Angular Components

Using code navigation (F12 for VS Code) we are now able to inspect the definition of RowClassRules and quickly see the type information in our editor.

Fully Typed Angular Components

Note that we are now able to see the required format of the row class rules object without having to find the definition online. While we will still want to visit the docs for more information and examples, we are not forced to, just to see the name of properties. This should help speed up development by reducing the amount of context switching and documentation searching.

Real Time Error Reporting

The new typings will also enable you to quickly and confidently update code as if you provide the wrong type you will immediately be notified.

Previously you would have to let your app recompile and inspect the grid in your browser. Now you will be able to correct the error even before the app compiles.

Fully Typed Angular Components

Code Completion

There are improvements when we are working with @Output events too as the $events parameter is now strongly typed. For example, let's add an event handler for the gridsizeChanged event.

If you hover over the gridSizeChanged event in the template we see that the type of the event is GridSizeChangedEvent.

Fully Typed Angular Components

We can then use this interface in our event handler and write code against the interface, taking advantage of code completion. No longer will you need to console.log($event) in the dev tools to see which properties are available!

Fully Typed Angular Components

View the new Typings in Action

Watch On YouTube

Developer Notes

Boolean Properties

The grid components have many boolean properties and we have set up the components so that you are still able to set these using the shorthand notation. By this we mean enableCharts is equivalent in behaviour to [enableCharts]=true.

<ag-grid-angular    
  enableCharts
></ag-grid-angular>

Enter fullscreen mode Exit fullscreen mode

This is made possible via Input Setter Coercion as without it, the attribute enableCharts is interpreted as [enableCharts]="''". This would then fail the type check as the empty string is not a boolean type.

StrictNullChecks and the async pipe

When you enable strictTemplates and the TypeScript flag strictNullChecks you may find you have issues when setting some Inputs via Observables with the async pipe. The Angular documentation covers this in detail here.

For grid Inputs rowData and columnDefs we explicitly accept null values which means the following is valid: [rowData]= rowData$ | async.

Boolean properties accept null as equivalent to false.

As an example, if you set up your rowHeight as follows:

rowHeight$: Observable<number>;

Enter fullscreen mode Exit fullscreen mode

And then pass this to the grid component.

<ag-grid-angular
  [rowHeight]="rowHeight$ | async"
></ag-grid-angular>

Enter fullscreen mode Exit fullscreen mode

If you have both strictTemplates and the TypeScript flag strictNullChecks enabled you will get a compilation error of:

Type 'null' is not assignable to type 'number | undefined'.
    [rowHeight]="rowHeight$ | async"

Enter fullscreen mode Exit fullscreen mode

This occurs because the async pipe can return null as a value when the Observable has not yet fired a value. With strict null checking null cannot be assigned to the type of number | undefined.

For AG Grid v25 and below this was not an error as the inputs all had type any and so null was silently accepted by the Input.

Potential Workarounds

The Angular documentation suggests potential workarounds depending on what is right for your application. However, in most cases, we would recommend providing a default value to use when the async pipe returns null.

In our example, we could provide a default row height of 50.

   [rowHeight]="(rowHeight$ | async) || 50"

Enter fullscreen mode Exit fullscreen mode

How are the Typings Applied?

You may be wondering why it has taken to v26 to have accurate types for the Angular components. To answer that it is important to understand that the Angular components are a hybrid of handwritten code and auto-generated properties.

At the time of writing, there are 282 Inputs and 72 Outputs on the grid component and a further 130 Inputs on the column component. As a result, we auto-generate the properties to avoid having to manually keep these in sync with the ever-changing GridOptions and ColDef interfaces.

In previous versions of the generation script, we had no way of knowing what the types were for each property. As a result, we could only add a generic Input and Output for each property.

@Input() public _PROPTERY_NAME_ : any = undefined;

@Output() public _PROPTERY_NAME_: EventEmitter<any> = new EventEmitter<any>();

Enter fullscreen mode Exit fullscreen mode

However, we have now updated the script to use the Typescript parser to build a type lookup for all of the interface properties. This has enabled us to apply the real typing for each Input and Output by looking up the type for the given property name.

@Input() public _PROPTERY_NAME_ : _INPUT_TYPE_ = undefined;

@Output() public _PROPTERY_NAME_: EventEmitter<_OUTPUT_TYPE_> = new EventEmitter<_OUTPUT_TYPE_>();

Enter fullscreen mode Exit fullscreen mode

By the same mechanism, we are also able to bring across any JSDoc comments and any deprecation annotations to the Angular components as soon as they are applied to the corresponding Typescript interface.

Future Proof Typings and Public Exports

The beauty of this approach is that the Angular types are future-proofed as they are updated with every internal build of AG Grid. Any changes to the GridOptions interface are immediately reflected in the <ag-grid-angular> component.

This also ensures that new Interfaces are correctly exported from ag-grid-community for use in your applications. This is because ag-grid-angular uses the public exports from ag-grid-community and so the internal build will now fail if the interfaces have not been exported. This benefits all Typescript users of AG Grid regardless of which framework they use.

Conclusion

We hope that you will find these new accurate typings for the Angular components <ag-grid-angular> and <ag-grid-column> helpful and that they will improve your developer experience when working with AG Grid. We would love to hear your feedback!

Learn more about AG Grid's Angular Support here.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .