ng-template - typed variable
There is an easy workaround to get the IDE to play along and also have code completion using a user-defined type guard:
Create a function in your class which takes the variable as an argument and returns the same variable:
export class CardComponent {
...
public video = (item: Video) => item;
}
Now simply wrap the variable in your template with the function:
<h5 class="tile__type">{{video(content).type}}</h5>
I created a helper directive to solve this.
import { Directive, Input, TemplateRef } from '@angular/core';
@Directive({selector: 'ng-template[typedTemplate]'})
export class TypedTemplateDirective<TypeToken> {
// how you tell the directive what the type should be
@Input('typedTemplate')
typeToken: TypeToken;
// the directive gets the template from Angular
constructor(private contentTemplate: TemplateRef<TypeToken>) {
}
// this magic is how we tell Angular the context type for this directive, which then propagates down to the type of the template
static ngTemplateContextGuard<TypeToken>(dir: TypedTemplateDirective<TypeToken>, ctx: unknown): ctx is TypeToken{ return true; }
}
Use it like this
<!-- typedTemplate is the directive, typeToken is an object on our component -->
<ng-template #someTemplate [typedTemplate]="typeToken" let-param="param">
{{param}}
</ng-template>
And in the component
// here we create typeToken. the value doesn't matter as it's never used, but the type of this variable defines the types of all template parameters.
typeToken: { param: string };
There is no type inference for let-*
variables. The let-
context is part of the micro syntax parser for Angular, and an IDE can not infer the type as there is no clear origin.
https://gist.github.com/mhevery/d3530294cff2e4a1b3fe15ff75d08855
You can try to silence the IDE warning using $any()
https://angular.io/guide/template-syntax#the-any-type-cast-function
<ng-template #tileTemplate let-content>
<h5 class="tile__type">{{$any(content).type}}</h5>
</ng-template>
You can force type inference by using a function
<ng-template #tileTemplate let-content>
<h5 class="tile__type">{{toVideo(content).type}}</h5>
</ng-template>
public toVideo(value: any): Video { return value as Video; }