Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to add a type assertion / annotation to a template input variable?

Background

I have a template that looks like this (I'm using some component that uses this as the basis for a repeated item, it's the <p-pickList>, but the question is not specific about that component, just as an example)

For background, let's say I have a type Foo and my component has a foos: Foo[], I'm feeding it to the <p-pickList> component under the [source] attribute and its doing the internal *ngFor for it, all I have to do is provide a template

 <ng-template let-foo pTemplate="item">    ...    {{ foo.anythingGoesHereWithNoWarningAndNoAutocomplete }} 

However, the type information on foo seems to be lost.

I'm a big fan of type safety and I like that Intellij (or any other editor) can show me a warning if inside the template I do something like specifying an invalid attribute of foo

If I had a regular *ngFor, it would infer the type of foo

<div *ngFor="let foo of foos">   {{ foo.autoCompleteWorksInMostIDEsAsWellAsWarningIfInvalidProp }} 

Questions:

  1. Is there any syntax that will allow me to hint the type of let-foo? (and hopefully most IDE's will recognize).

  2. If I don't want to rely on IDE's, is there a way to have the ng compiler type check foo (declared by let-foo)?

tl;dr is there a syntax that let me type annotate the template input variable? e.g. something like this made up syntax?

let-foo="$implicit as Foo" or let-foo-type="Foo"?

Workaround

One silly idea is to have an identity function in my component, e.g.

identity(foo: Foo): Foo {   return foo; } 

But doing

{{ identity(foo).fooProp }} 

Is not a big improvement over

{{ (foo as Foo).fooProp }}` 
like image 552
Eran Medan Avatar asked Aug 29 '18 22:08

Eran Medan


People also ask

What is Template input variable?

Use template variables to perform tasks such as respond to user input or finely tune your application's forms. A template variable can refer to the following: a DOM element within a template. a directive or component. a TemplateRef from an ng-template.

Which keyword is used to set a variable in the template?

We declare Template reference variables using # followed by the name of the variable ( #variable ).


Video Answer


1 Answers

Let's see what angular has similar to that and how it work!

<p *ngFor="let number of [{v: 101},{v: 102}, {v: 103}]">{{number.v}}</p> 

We can rewrite it without * magic

<ng-template ngFor let-number [ngForOf]="[{v: 101},{v: 102}, {v: 103}]">   <p>{{number.v}}</p> </ng-template> 

Without watchers (ngDoCheck) it can be the same as (but ngTemplateOutlet have no typecheck):

<ng-template let-number #templateRef>   <p>{{number.v}}</p> </ng-template> <ng-container *ngTemplateOutlet="templateRef; context: {$implicit: {v: 101}}"></ng-container> <ng-container *ngTemplateOutlet="templateRef; context: {$implicit: {v: 102}}"></ng-container> <ng-container *ngTemplateOutlet="templateRef; context: {$implicit: {v: 103}}"></ng-container> 

Or we can create it by ourselves

// template <button (click)=create(templateRef)>create</button> 
// TS constructor(private _viewContainerRef: ViewContainerRef) { ... }  create(templateRef: TemplateRef<{$implicit: {v: number;}}>) {     this._viewContainerRef.createEmbeddedView(templateRef, {$implicit: {v: 101}});     this._viewContainerRef.createEmbeddedView(templateRef, {$implicit: {v: 102}});     this._viewContainerRef.createEmbeddedView(templateRef, {$implicit: {v: 103}}); } 

TL;DR

Template typecheck magic happens inside viewContainerRef.createEmbeddedView. (for example ngFor); But it assume what templateRef accepts.

Angular can compile in AOT:

<p *ngFor="let num of [{v:1}, {v:2}]">   {{num.does.not.exist.completly}} </p> 

So as i understood we should assume what types templates have but do check when template is instantiated (by createEmbeddedView);

like image 138
Buggy Avatar answered Sep 21 '22 15:09

Buggy