Type checking in Angular 2 templates

AngularTypescriptAngular2 Template

Angular Problem Overview


We are building an application in Angular 2 and TypeScript. We try to statically check types where it is possible. Is there any way to check types in templates? Consider the following fragment:

<foo [data]="dataObj"></foo>

Assume that data in Foo component has some type TData. However, by default, nothing prevents me from passing dataObj that does not conform to TData. Is there a typescript extension for Angular templates that would verify the types in such a case?

Angular Solutions


Solution 1 - Angular

Since Angular 9 the solution is strictTemplates flag of Angular compile options, see Strict mode section of Template type checking guide. Enable the flag in tsconfig.json file:

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

Original answer:

Unfortunately, It seems that current Angular version doesn't check types of component inputs and events. You can use AOT compilation and enable fullTemplateTypeCheck angular compiler option, which performs some template type checking.

Enable fullTemplateTypeCheck option in src/tsconfig.app.json

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

And build (or serve) your project with --aot option

ng build --aot

What about inputs and events type checking, I found two issues on angular bug tracker (issue1 and issue2). As I understand, the solution of the problem depends on renderer implementation, and more likely that the problem may be fixed in next version of angular renderer, called Ivy. Here is feature request for inputs type checking in ivy renderer.

Solution 2 - Angular

WebStorm from Jetbrains can do that.

My original answer: > I don't think there's a reliable way to do that without doing some > think like React does with the JSX or TSX extension to the language. > > The typescript compiler doesn't know about your HTML files, and will > just ignore them. Also, there's no strong coupling between your > templates and the Controller code... there's nothing preventing you > from reusing the same template across several controllers.

Solution 3 - Angular

to quote the official statement:

> In the template type-checking phase, the Angular template compiler uses the TypeScript compiler to validate the binding expressions in templates. > > Template validation produces error messages when a type error is detected in a template binding expression, similar to how type errors are reported by the TypeScript compiler against code in a .ts file.

More at:

Angular Template checking https://angular.io/guide/aot-compiler#binding-expression-validation

Yet to activate it, you should build the app, by

ng build --aot

or

ng build --prod

but you can also activate it without building:

ng serve --aot

Solution 4 - Angular

I think an IDE or linter might catch this for you, but if someone really needs this, one option would be to create a Pipe to do the type checking at run time.

@Pipe({ name: 'typeCheck' })
export class TypeCheckPipe implements PipeTransform {

  transform(value: any, classType: object): any[] {
    if (value &&
      !(value instanceof classType)
    ) {
        throw new TypeError("Input is not instanceof " + classType + 
                            " but was " + typeof(value));
    }
    return value;
  }
}

You can use it in a component template like this:

<custom-component [coolInput]="coolInput | typeCheck:coolInputClass"></custom-component>

The only catch I found is that I'm not sure how to inject the class function into the template other than as an instance of the component.

@Component({
  selector: 'my-app',
  template: `
  <div>
    <custom-component [coolInput]="coolInput | typeCheck:coolInputClass"></custom-component>
  </div>
  `,
})
export class App {
  coolInput: CoolInput;
  coolInputClass: object = CoolInput;

  constructor() {
    this.coolInput = "This is the wrong type";
  }
}

Here is a Plunker illustrating the working error message (thrown via Zone). https://plnkr.co/edit/WhoKSdoKUFvNbU3zWJy6?p=preview

Solution 5 - Angular

If you are using visual studio code, you could try out the language service extension. Its still under heavy development, and you could consider it in beta. But when I would definitely say that it have made me more productive. Not only its type checking, but also cmd + clicking components to go to their source.

If I am not mistaken, this project will eventually be merged to vscode it self when its somewhat stable as its in vscode's best interest to keep angular developers productive.

You can rest assured about the extension's support because it's being worked on by the angular team. For more information checkout this readme

Edit: sublime text and webstorm support this too.

Solution 6 - Angular

Your components Input() should have the type. Let's say you have a list component

import {Component, Input, OnInit } from '@angular/core';

import { Items } from '../../../services/Items';

@Component({
  selector: 'my-list',
  templateUrl: './my-list.component.html',
  styleUrls: ['./my-list.component.scss'],
})
export class CategoryListComponent implements OnInit {
  @Input() items: Items;

  constructor() { }

  ngOnInit() { }
}

"Items" should be defined as a interface and imported

export interface List {
  name: string,
  children: Items[]
}

export interface Item {
  name: string;
  slug: string;
  imageUrl: string;
  children: Item[];
}

now you can use it like this

<my-list [items]="items"></my-list>

Solution 7 - Angular

You could use a Pipe:

export class ObjectTypePipe implements PipeTransform {
    transform(value: any, args?: any): string {
	    if (value != undefined && value != null) {
		    return value.constructor.name.toString();
	    }
	    return "";
    }
}

This would then allow you to do a string comparison.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjfuView Question on Stackoverflow
Solution 1 - AngularValeriy KatkovView Answer on Stackoverflow
Solution 2 - AngularVictor HögemannView Answer on Stackoverflow
Solution 3 - AngularSinisa RudanView Answer on Stackoverflow
Solution 4 - AngularkevinrstoneView Answer on Stackoverflow
Solution 5 - AngularrealappieView Answer on Stackoverflow
Solution 6 - AngularMackelitoView Answer on Stackoverflow
Solution 7 - AngularCorriganView Answer on Stackoverflow